Gil*_*esz 2 x86 multithreading interrupt atomicity pintos
这段代码来自 Pintos 源码:https : //www.cs.usfca.edu/~benson/cs326/pintos/pintos/src/threads/synch.c
void
sema_down (struct semaphore *sema)
{
enum intr_level old_level;
ASSERT (sema != NULL);
ASSERT (!intr_context ());
old_level = intr_disable ();
while (sema->value == 0)
{
list_push_back (&sema->waiters, &thread_current ()->elem);
thread_block ();
}
sema->value--;
intr_set_level (old_level);
}
Run Code Online (Sandbox Code Playgroud)
采取信号量的事实是sema->value--;。如果它有效,它必须是一个原子操作。我们怎么知道它实际上是原子操作?我知道现代 CPU 保证对齐的内存操作(对于字/双字/四字 - 它取决于)是原子的。但是,在这里,我不相信为什么它是原子的。
TL:DR:只要您不计算使用 DMA 观察内存的系统设备,如果您在 UP 系统上禁用中断,那么任何事情都是原子的。
注意操作周围的intr_disable ();/ intr_set_level (old_level);。
现代 CPU 保证对齐的内存操作是原子的
对于多线程观察者,这仅适用于单独的加载或存储,不适用于读-修改-写操作。
对于原子性的事物,我们必须考虑我们关心哪些潜在的观察者。重要的是,没有任何东西可以观察到部分发生的操作。实现这一目标的最直接方法是使操作在物理/电气上是瞬时的,并同时影响所有位(例如,并行总线上的加载或存储在时钟周期的边界从未启动变为完成,因此它是“免费”的原子,直到并行总线的宽度)。这对于读-修改-写来说是不可能的,我们能做的最好的事情就是阻止观察者在负载和存储之间查看。
我对 x86上的原子性的回答以不同的方式解释了同样的事情,关于原子意味着什么。
在单处理器 (UP) 系统中,唯一的异步观察者是其他系统设备(例如 DMA)和中断处理程序。如果我们可以排除非 CPU 观察者写入我们的信号量,那么我们关心的只是中断的原子性。
此代码采用简单的方法并禁用中断。这不是必需的(或者至少如果我们用 asm 编写就不需要)。
中断是在两条指令之间处理的,永远不会在一条指令的中间。机器的架构状态要么包括内存减量,dec [mem]要么不包括,因为要么运行要么没有。我们实际上不需要lock dec [mem]这个。
顺便说一句,这是cmpxchg没有lock前缀的用例。我总是想知道为什么他们不只是在 中lock隐含cmpxchg,原因是 UP 系统通常不需要lock前缀。
此规则的例外是可以记录部分进度的可中断指令,例如rep movsb或vpgather/vpscatter 参见在执行过程中中断指令 这些不会是原子的。即使唯一的观察者是同一内核上的其他代码,也会中断。只会rep whatever发生或不发生的一次迭代,或聚集或分散的单个元素。
大多数 SIMD 指令无法记录部分进度,因此例如vmovdqu ymm0, [rdi],从它运行的核心的 PoV 中完全发生或根本不发生。(但当然不能保证原子性。系统中的其他观察者,如 DMA 或 MMIO,或其他内核。那是正常加载/存储原子性保证很重要的时候。)
没有可靠的方法来确保编译器发出dec [value]而不是这样的:
mov eax, [value]
;; interrupt here = bad
dec eax
;; interrupt here = bad
mov [value], eax
Run Code Online (Sandbox Code Playgroud)
ISO C11/C++11 没有提供一种方法来请求关于信号处理程序/中断的原子性,但不是其他线程。它们确实提供atomic_signal_fence了一个编译器屏障(相对于 thread_fence 作为屏障,其他线程/核心),但屏障不能创建原子性,只能控制顺序。其他操作。
C11/C++11volatile sig_atomic_t确实有这个想法,但它只为单独的加载/存储提供原子性,而不是 RMW。 它是intx86 Linux 上的 typedef 。请参阅该问题以了解标准中的一些引用。
在特定实现上,gcc -Wa,-momit-lock-prefix=yes将省略所有锁前缀。(GAS 2.28 docs)这对于单线程代码或单处理器机器是安全的,如果您的代码不包含需要在 MMIO 位置执行原子 RMW 的设备驱动程序硬件访问,或者使用虚拟机lock add作为更快mfence。
但是这在需要在 SMP 机器上运行的多线程程序中是不可用的,如果您在线程之间以及线程和信号处理程序之间有一些原子 RMW。
| 归档时间: |
|
| 查看次数: |
950 次 |
| 最近记录: |