Ostep 26 Concurrency Introduction

这章主要介绍了线程和并发的概念

并发

并发执行下,我们需要考虑2种情况。

数据竞争

为什么并发下会有数据竞争问题?

比如最朴素的场景,2个线程同时执行i++,最终的结果总是不如预期,实际上,是因为i++本身在执行时是3条汇编指令:

mov 0x8049a1c, %eax
add $0x1, %eax
mov %eax, 0x8049a1c

比如现在要执行到50+1,此时当线程T1执行该指令到一半,add执行完后,被操作系统调度机制挂起,开始执行T2,T2读到的数据依旧是旧的也就是50,然后T1执行,将内存修改为51,T2再执行,也依然是将内存修改为51,我们就可以看做一次操作“丢失了”。

我们可以看到,并发问题总在多线程更新共享变量时产生

这种场景,书中总结也就是我们之前常说或者听到过的,竞态条件race condition(或者更具体地说,是数据竞态data race)。

包含静态条件的代码,称为:critical section (临界代码)。

处理这种问题的方式就是,我们需要使这段代码mutual exclusion (互斥),也就是提供Atomicity(原子性)

条件变量

并发还有一种场景,即互相等待的场景,T1线程需要等待T2执行完后再执行,为了实现这种效果,我们还需要提供condition variables(条件变量)。

线程

以前上课学的一句话比较经典:

线程是操作系统(或者说CPU)调度(执行)的最小单位,进程是操作系统分配资源的最小单位

线程和进程的主要区别就是,线程之间一定程度上共享进程的页表(也就是进程数据),是更轻量级的执行单位。

线程的几个好处:

  1. 共享进程页表(即共享内存)。
  2. 面对进程中的那些I/O任务,使用线程去进行I/O任务会有更好的表现(线程阻塞等待I/O执行,进程中其他线程依旧可以使用CPU计算资源)

线程的缺点:

  1. 在进程内存中,线程就必须有自己独享的栈以及一些私有数据了thread-local storage
  2. 线程切换的上下文依旧很重,进程有PCB,线程也有自己的TCB,并且更多了。

总结

​ 综上,从进程实际要执行的事情以及日常的任务(I/O)来看,线程这一轻量级执行单元的诞生和大规模使用基本是必然的。尽管进程也可以达到如此效果,但是又要做到进程之间的内存共享会是一个更麻烦的事,并且也会破坏进程自己的定义和内存完整性。

​ 同时,结合之前来看,cow(写时复制)对于线程的创建起到了多大的便利。

​ 以及,在大量使用线程并行执行的情况下,解决并发问题是多么的重要。

版权声明:除特殊说明,博客文章均为intotw原创,依据CC BY-SA 4.0许可证进行授权,转载请附上出处链接及本声明。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇