如何从概念上解释操作系统级别的线程同步机制?

时间:2019-06-23 06:42:49

标签: multithreading thread-safety thread-synchronization

SO以及整个Internet上的许多论坛上都有很多关于线程同步的讨论。但是,从概念上讲,我找不到准确的信息来了解它在OS级别的发生情况。

众所周知,线程同步对象有以下几种类型:

  1. Mutex
  2. 信号量
  3. 关键部分

据我所知,一次允许多个线程修改资源(例如,两个线程同时更改内存中变量的位)不是一个好主意,因此我们使用这些对象。但是,当多个线程尝试访问这些对象时,也应该发生完全相同的事情。

  1. 核心真正发生了什么?操作系统如何实现这一目标?

  2. 我们如何才能在概念层面上向某人解释这一点(而不是在硬件或组装层面上的细节)?

1 个答案:

答案 0 :(得分:1)

首先让我们总结一下线程的根本问题是什么-两个线程试图同时访问同一块内存。您可以想象,当发生这种情况时,我们不能保证内存处于有效状态,并且我们的程序可能不正确。

试图保持很高的水平,处理器工作的部分方式是抛出中断,这些中断基本上告诉线程停止正在执行的操作并执行其他操作。这就是很多线程问题所在。线程可以在任务中途中断。想象一下,一个线程在操作过程中被中断,并且由于该线程尚未完成其任务而存在一些中间垃圾值。可能会出现另一个线程来读取此值,并破坏程序的正确性。

OS通过Atomic指令实现此目的。在不深入讨论细节的情况下,请确保存在一些可以保证完成或未完成的指令。这意味着,如果线程检查指令的结果,则不会看到中间结果。因此,原子添加方法将在添加之前或之后显示值,但在添加期间(可能处于中间状态)则不显示值。

现在,如果您有一些原子指令,您可能可以想象,可以在这些线程的背面构建处理线程和线程安全性的更高级别的抽象。也许是用test和set原语创建的锁中最基本的示例。看看这篇维基百科文章https://en.wikipedia.org/wiki/Test-and-set。现在可能很多,因为这些事情变得非常复杂。但我将尝试给出一个澄清的例子。如果您有两个正在运行的进程正在尝试访问代码的某些部分,那么非常幼稚的解决方案是创建一个锁变量

boolean isLocked = false;

任何时候只要进程尝试获取此锁,您都只能检查isLocked == false并等到isLocked == true之后再执行一些代码。例如...

while(isLocked){
//wait for isLocked == false
} 
isLocked = true;
// execute the code you want to be locked
isLocked = false;

当然,我们知道诸如设置或读取布尔值之类的简单操作可能会中断并导致线程混乱。因此,开发内核,处理器和硬件的优秀人员创建了原子测试和设置操作,该操作返回布尔值的旧值并将新值设置为true。因此,您当然可以通过执行类似的操作来实现上面的锁。

 while(testAndSet(isLocked)){ //wait until the old value returned is
 false so the lock is unlocked } //do some critical stuff

 //unlock after you did the critical stuff lock = false;

我仅在上面展示了基本锁的实现,以证明有可能在原子指令上构建更高级别的抽象。在我看来,原子指令的级别尽可能低,而无需研究硬件细节。您可以想象,尽管在硬件中,当读取内存时,硬件必须以某种方式设置某种标志,从而阻止另一个线程访问同一内存。

希望有帮助!