gpt4 book ai didi

multithreading - 发出信号量必须是原子的。 Pintos的sema_down安全吗?

转载 作者:行者123 更新时间:2023-12-03 12:48:59 27 4
gpt4 key购买 nike

这段代码来自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);
}

接收信号量的事实是 sema->value--;。如果可行,则必须是原子操作。
我们怎么知道实际上是原子操作?我知道现代CPU保证对齐的内存操作(对于字/双字/四字,取决于它)是原子的。但是,在这里,我不相信为什么它是原子的。

最佳答案

TL:DR:只要在不计入使用DMA观察内存的系统设备的情况下,只要在UP系统上禁用了中断,就可以执行任何操作。
注意操作周围的intr_disable ();/intr_set_level (old_level);

modern CPU guarantees that aligned memory operation are atomic


对于多线程观察者,这仅适用于单独的加载或存储,而不适用于读取-修改-写入操作。

要使事情变得原子化,我们必须考虑我们关心的潜在观察者。重要的是,没有人能观察到该操作已部分发生。实现此目的最直接的方法是物理/电气瞬时操作,并同时影响所有位(例如,并行总线上的负载或存储在时钟周期的边界从未启动变为完成),因此直到并行总线的宽度为止都是“免费”的。对于read-modify-write来说这是不可能的,在这种情况下,我们能做的最好的事情就是阻止观察者在加载和存储之间寻找。
我对 Atomicity on x86的回答以不同的方式解释了同一件事,即原子是什么意思。

在单处理器(UP)系统中,唯一的异步观察者是其他系统设备(例如DMA)和中断处理程序。如果我们可以将非CPU观察者排除在写信号量之外,那么这仅仅是我们关心的中断的原子性。
该代码采用了简单的方法,并禁用了中断。这不是必需的(或者至少如果我们使用asm编写,则没有必要)。
An interrupt is handled between two instructions,永远不要在指令中间。机器的体系结构状态要么包含内存减少,要么不包括内存减少,因为 dec [mem]运行或没有运行。我们实际上不需要 lock dec [mem]
顺便说一句,这是 cmpxchg without a lock prefix的用例。我一直想知道为什么他们不只是将 lock隐含在 cmpxchg中,原因是UP系统通常不需要 lock前缀。
该规则的异常(exception)是可记录部分进度的可中断指令,例如rep movsbvpgather/vpscatter 请参阅 Interrupting instruction in the middle of execution这些不会是原子的。即使唯一的观察者是同一内核上的其他代码,也会中断。不论是否发生 rep whatever的单个迭代,或聚集或散布的单个元素,都不会发生。
大多数SIMD指令无法记录部分进度,因此,例如 vmovdqu ymm0, [rdi]是完全发生还是根本没有发生在其运行的内核的PoV上。 (但是,当然不能保证以原子方式维护系统中的其他观察者,例如DMA或MMIO或其他内核。这是 normal load/store atomicity guarantees的问题。)

没有可靠的方法来确保编译器发出dec [value]而不是类似以下的代码:
mov   eax, [value]
;; interrupt here = bad
dec eax
;; interrupt here = bad
mov [value], eax
ISO C11/C++ 11没有提供关于信号处理程序/中断的请求原子性的方法,但没有提供其他线程的方法。它们的确提供了 atomic_signal_fence作为编译器屏障(相对于thread_fence作为屏障对其他线程/核心),但是屏障不能产生原子性,只能控制排序wrt。其他操作。
C11/C++ 11 volatile sig_atomic_t确实有这个想法,但它仅为单独的加载/存储提供原子性,而不为RMW提供原子性。 It's a typedef for int on x86 Linux. See that question for some quotes from the standard
在特定实现中, gcc -Wa,-momit-lock-prefix=yes将忽略所有锁前缀。 ( GAS 2.28 docs)如果您的代码不包含需要在MMIO位置执行原子RMW的设备驱动程序硬件访问,或者使用伪 lock add作为更快的速度,则此方法对于单线程代码或单处理器计算机是安全的 mfence
但这在需要在SMP机器上运行的多线程程序中是无法使用的,如果您在线程之间以及在线程与信号处理程序之间有一些原子RMW。

关于multithreading - 发出信号量必须是原子的。 Pintos的sema_down安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39358761/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com