当多个线程试图同时访问临界区时会发生什么?
What happens when multiple threads try to access a critical section exactly at the same time?
我一直在努力寻找答案,我所能找到的就是一旦一个线程到达临界区,它就会在其他线程之前锁定它(或者一些其他的锁定机制被用来锁定临界区)。
但这意味着线程并没有真正准确地在同一微秒内到达 CS。
虽然我估计很少见,但真的会发生吗,在这种情况下会发生什么?
我可以简单地假设程序会出现故障吗?
注意:我指的是多核 CPU。
谢谢。
我认为您忽略了像信号量这样的基本锁定原语的要点。如果使用了正确的原语,并且使用正确,那么线程的时间并不重要。它们很可能是同时发生的。操作系统保证没有两个线程会进入临界区。即使在多核机器上,这个位也是专门实现的(甚至有很多技巧)来获得这种保证。
具体解决您的顾虑:
But that implies that the threads didn't really reach the CS exactly at the same microsecond.
没有。其他线程本可以在同一微秒内到达,但如果锁定机制正确,则只有一个竞争线程将“进入”临界区,其他线程将等待。
Although I guess it is quite rare, can it really happen, and what happens in this situation?
无论是否罕见,如果使用正确的锁定原语,并且使用正确,则没有两个线程会进入临界区。
Can I simply assume the the program will malfunction?
理想情况下,程序不应出现故障。但是任何代码都会有错误 - 您的代码和信号量的操作系统代码也是如此。因此可以安全地假设在某些边缘情况下程序确实会出现故障。但这个假设一般适用于任何代码。
锁定和关键部分很难正确实现。因此,出于非学术目的,我们应该始终使用系统提供的锁定原语。所有操作系统都公开诸如信号量之类的东西,大多数编程语言都有使用的方法。一些编程语言有自己的轻量级实现,这些实现提供了更软的保证但性能更高。正如我所说,在做关键部分时,选择正确的东西并正确地实现它是至关重要的。
...But that implies that the threads didn't really reach the CS exactly at the same microsecond.
简答;内存系统硬件 使得两个不同的处理器不可能同时访问同一个内存位置。我不是计算机架构师,所以我无法解释它是如何工作的,但是内存系统 序列化 各种 CPU 对共享主内存的所有访问]在多CPU系统中。
“进入临界区”意味着锁定互斥量,互斥量基本上只是共享内存中的一个标志,可以通过特定协议访问。
缓存一致性协议的任务是确保不会同时在同一内存块(缓存行)上进行 2 次写入。使用 MESI,同一缓存行可以有多个读取器,但只有 1 个写入器。
所以如果2个线程同时要写入同一个缓存行,他们的请求将被缓存一致性协议序列化。
大多数 CPU 架构都支持像 CAS 这样的原子操作。在 X86 上,这可以使用锁定前缀来完成。 CPU 以 CAS 指令开始时将锁定缓存行,并且在完成原子操作之前不会响应来自其他内核的缓存一致性请求。
因此,如果您有 2 个 CPU 都想执行 CAS,则这些操作由底层硬件序列化。
我一直在努力寻找答案,我所能找到的就是一旦一个线程到达临界区,它就会在其他线程之前锁定它(或者一些其他的锁定机制被用来锁定临界区)。
但这意味着线程并没有真正准确地在同一微秒内到达 CS。
虽然我估计很少见,但真的会发生吗,在这种情况下会发生什么?
我可以简单地假设程序会出现故障吗?
注意:我指的是多核 CPU。
谢谢。
我认为您忽略了像信号量这样的基本锁定原语的要点。如果使用了正确的原语,并且使用正确,那么线程的时间并不重要。它们很可能是同时发生的。操作系统保证没有两个线程会进入临界区。即使在多核机器上,这个位也是专门实现的(甚至有很多技巧)来获得这种保证。
具体解决您的顾虑:
But that implies that the threads didn't really reach the CS exactly at the same microsecond.
没有。其他线程本可以在同一微秒内到达,但如果锁定机制正确,则只有一个竞争线程将“进入”临界区,其他线程将等待。
Although I guess it is quite rare, can it really happen, and what happens in this situation?
无论是否罕见,如果使用正确的锁定原语,并且使用正确,则没有两个线程会进入临界区。
Can I simply assume the the program will malfunction?
理想情况下,程序不应出现故障。但是任何代码都会有错误 - 您的代码和信号量的操作系统代码也是如此。因此可以安全地假设在某些边缘情况下程序确实会出现故障。但这个假设一般适用于任何代码。
锁定和关键部分很难正确实现。因此,出于非学术目的,我们应该始终使用系统提供的锁定原语。所有操作系统都公开诸如信号量之类的东西,大多数编程语言都有使用的方法。一些编程语言有自己的轻量级实现,这些实现提供了更软的保证但性能更高。正如我所说,在做关键部分时,选择正确的东西并正确地实现它是至关重要的。
...But that implies that the threads didn't really reach the CS exactly at the same microsecond.
简答;内存系统硬件 使得两个不同的处理器不可能同时访问同一个内存位置。我不是计算机架构师,所以我无法解释它是如何工作的,但是内存系统 序列化 各种 CPU 对共享主内存的所有访问]在多CPU系统中。
“进入临界区”意味着锁定互斥量,互斥量基本上只是共享内存中的一个标志,可以通过特定协议访问。
缓存一致性协议的任务是确保不会同时在同一内存块(缓存行)上进行 2 次写入。使用 MESI,同一缓存行可以有多个读取器,但只有 1 个写入器。
所以如果2个线程同时要写入同一个缓存行,他们的请求将被缓存一致性协议序列化。
大多数 CPU 架构都支持像 CAS 这样的原子操作。在 X86 上,这可以使用锁定前缀来完成。 CPU 以 CAS 指令开始时将锁定缓存行,并且在完成原子操作之前不会响应来自其他内核的缓存一致性请求。
因此,如果您有 2 个 CPU 都想执行 CAS,则这些操作由底层硬件序列化。