我正在阅读有关信号量及其操作的文本。作者强调信号量的wait()
和post()
操作应该原子执行,否则可能违反线程互斥。谁能给我解释一下他的意思?顺便说一句,我是多线程的新手
2 回答
上下文切换的操作,其中一个任务/进程被内核替换为另一个,是异步和不确定的。
让我们检查以下代码:
x++;
看起来很简单,哈?但是,如果 x 在不同的任务/进程之间共享,则此代码容易出现同步错误。
要理解这一点,您必须了解原子操作的概念。
原子操作是处理器可以在单个时钟上执行的指令。它通常涉及读取寄存器、写入寄存器等。
回到代码示例:当递增变量时,在幕后(汇编)实际发生的是 cpu 将变量的值读入寄存器。然后,它增加它。然后它将它保存回它从(内存)工具它的原始位置。
如您所见,像这样的简单操作涉及 3 个 cpu 步骤。上下文切换可以在这 3 个步骤之间发生。
让我们举一个需要增加同一个变量 x 的两个线程的例子。
让我们检查一个想象的(但可能的)场景的伪汇编代码
- 读取要注册的值(线程 1)
- 增加值(线程 1) CONTEXT SWITCH
- 读取要注册的值(线程 2)
- 增加值(线程 2)
- 保存值(线程 2) CONTEXT SWITCH
- 保存值(线程 1)
如果 x 是 3,现在看来它需要是 5,但它会是 4。
现在,让我们参考您的原始问题。信号量/互斥体实际上是一个变量。当一个进程想要接受它时,它会增加它。
是的,如果信号量上的wait()
和post()
操作没有原子地执行,线程的相互执行可能会被违反。
例如,考虑一个具有值S = 1
和进程的信号量,P1
并P2
尝试wait()
同时执行如下,
在 time T0
,T1
process P1
,分别P2
找到 semaphore 的值,S = 1
然后递减 semaphore 以获取锁并同时进入临界区,违反了线程的相互执行。
建议在获得锁之前 使用自旋锁wait()
和post()
自旋锁之间的原子性。