如何从概念上解释OS级别的线程同步机制?

How to explain thread synchronization mechanism at OS level conceptually?

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

我们都知道有这些类型的线程同步对象:

  1. 互斥
  2. 信号量
  3. 临界区

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

  1. 核心到底发生了什么? OS 究竟是如何做到这一点的?

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

首先让我们总结一下线程的根本问题究竟是什么——两个线程试图同时访问同一块内存。你可以想象,当这种情况发生时,我们无法保证一块内存处于有效状态,我们的程序可能会出错。

为了保持这个非常高的水平,处理器工作的部分方式是抛出中断,这基本上告诉线程停止正在做的事情并做其他事情。这就是线程的大部分问题所在。线程可以在任务中间被中断。想象一下,一个线程在一个操作的中间被中断,并且由于线程没有完成它的任务而存在一些中间垃圾值。另一个线程可能会出现并读取该值并破坏程序的正确性。

OS 使用原子指令实现了这一点。在不深入细节的情况下,想象一下有一些指令可以保证完成或不完成。这意味着如果线程检查指令的结果,它不会看到中间结果。因此,原子添加方法会在添加之前或添加之后显示值,但不会在添加期间显示它们可能处于某种中间状态。

现在,如果您有一些原子指令,您可能会想象您可以构建更高级别的抽象来处理线程和线程安全性。也许是使用测试和设置原语创建的锁中最基本的示例。看看这篇维基百科文章 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;

当然,我们知道像设置或读取布尔值这样简单的事情可能会被中断并导致线程混乱。因此,开发内核、处理器和硬件的优秀人士创建了一个原子测试和设置操作,该操作 returns 布尔值的旧值并将新值设置为 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;

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

希望对您有所帮助!