Concurrency: An Introduction
我们这里引入了thread(线程)的概念,与前面所说process(进程)的区别如下:
- 线程之间进行上下文切换地址空间保持不变。
- 每个线程都将有一个stack。
1. Why Use Threads?
在深入了解thread之前,首先需要知道为什么要使用thread。至少有如下两个原因:
- parallelism
- to avoid blocking program progress due to slow I/O
上述两个原因你也可以使用多进程,但是线程共享一个地址空间,因此很容易共享数据,因此在构造这些类型的程序时多线程是很好的一个选择。对于在内存中几乎不需要共享数据结构的逻辑上独立的任务而言,多进程是一个更合理的选择。
2. An Example: Thread Creation
下图线程运行顺序不是唯一顺序。
下图所示一种情况,当线程被创造出来后就直接运行。
线程创造后如何运行取决于scheduler,它要是喜欢,“B”也可以在"A"前面打印出来。如下所示:
不过,引入了并发使得计算机变得更糟糕!
3. Why It Gets Worse: Shared Data
接下来谈谈线程在访问共享数据时如何交互。
看一下上面的代码,最终counter
的结果应该为2e7。期望的汇编结果如下:
但是,即使在单个处理器的机器上运行此代码都无法得到期望的结果:
为什么不能得到期望的结果呢?
4. The Heart Of The Problem: Uncontrolled Scheduling
为了理解为什么上述情况发生,我们就必须理解汇编器如何对counter
进行更新。
假设counter
地址为0x8049a1c,对其更新的汇编代码如下所示:
mov 0x8049a1c, %eax
add $0x1, %eax
mov %eax, 0x8049a1c
假设eax当前的值为50,线程1执行上述三条语句,当执行完前两条语句后,进程转换发生了,系统准备运行线程2。这时,线程1中的eax的值为51被保存起来,线程2开始运行上述三条语句,但是此时eax的值还是50,线程2执行完三条语句后eax的值为51。然后转换到线程1进行执行,但是此时对于线程1来说,它取出被保存的eax值,然后执行最后一条语句。简而言之就是:eax的值应该加2,但是最终的eax的值只加了1。这样,就产生了上述非理想情况。
下图所示可以更好地理解:
5. The Wish For Atomicity
解决上述问题的方法就是使用更强大的指令,只需一部即可完全完成我们需要做的一切,从而消除了不及时中断的可能性。
标签:语句,26,0x8049a1c,eax,线程,所示,Threads,习题 From: https://www.cnblogs.com/astralcon/p/16792715.html