如果线程在临界区或进入临界区会怎样?

What happens if a thread is in the critical section or entering the critical section?

我试图更好地理解一章,但对线程位于临界区或正在进入临界区时会发生什么感到困惑。有人可以解释或给我一个关于线程在这种情况下经历的过程的想法吗?谢谢你。

举个例子,假设你有一个数组,以及读写数组的多个线程;如果不同的线程同时读取和写入数组,它们会看到不一致的数据,这会导致问题。为了防止这些问题,您使用某种锁来保护数组 - 在对数组执行任何操作之前,线程会获取数组的锁,并且在使用完数组后,线程会释放数组的锁。

例如:

    acquire_array_lock();
    /** Critical section (code that does something with the array) **/
    release_array_lock();

关键部分的代码没有什么特别之处。它做任何它设计要做的事情(可能对数组进行排序,可能将数组中的所有数字相加,可能显示数组,等等)使用的代码与你可能用来在一个单一的做同样的事情的代码没有什么不同- 没有锁的线程系统。

唯一特殊的部分是获取和释放锁的代码。

有许多类型的锁(自旋锁、互斥锁、信号量),但它们都具有相同的基本原理——在获取它时,你有一些东西(例如变量)来确定一个线程 can/can' t 继续,然后(如果线程不能继续)某种等待或(如果线程可以继续)某种改变让其他人知道他们需要等待;当发布时,你有一些东西可以让其他人知道他们可以停止等待。

不同类型的锁之间的主要区别在于实现细节——使用什么样的数据来确定线程是否can/can不继续,以及线程如何等待。

对于最简单的锁(自旋锁),您可能只有一个 "yes/no" 标志,有点像这样(但不是字面意思):

acquire_lock(void) {
    while(myLock == 0) {
        // do nothing then retry
    }
    myLock = 1;
}

release_lock(void) {
    myLock = 0;
}

但是这不会起作用,因为两个或多个线程可以同时看到 myLock == 0 并认为它们都可以继续(然后在为时已晚之后执行 myLock = 1)。要解决此问题,您需要汇编语言或对原子操作的特殊语言支持(例如 "test and set" 或 "compare and exchange" 的特殊函数)。

之所以称为 "spinlock" 是因为(如果一个线程需要等待)它会浪费 CPU 时间不断地检查 ("spinning") 看它是否可以继续。线程可以告诉调度程序在释放锁之前不要给它任何 CPU 时间,而不是这样做(以避免浪费 CPU 时间);这就是互斥量的工作原理。