我正在阅读this,其中Robert Love提到互斥是使用内存屏障实现的,但我无法看到Linux实现互斥锁时使用的内存屏障指令。我想知道他是否指的是posix库中的互斥锁实现,它确实使用了内存屏障指令,这样它就不会相对于关键资源重新排序,我说的对吗?
s2j5cfk01#
Robert Love的答案适用于 * 任何领域 * 的互斥。你提到的Linux内核中的实现使用__mutex_fastpath_lock,它完成了大部分工作,通常使用汇编代码实现。例如,在x86_64上,它的实现可以是:
__mutex_fastpath_lock
20 static inline void __mutex_fastpath_lock(atomic_t *v, 21 void (*fail_fn)(atomic_t *)) 22 { 23 asm_volatile_goto(LOCK_PREFIX " decl %0\n" 24 " jns %l[exit]\n" 25 : : "m" (v->counter) 26 : "memory", "cc" 27 : exit); 28 fail_fn(v); 29 exit: 30 return; 31 }
20 static inline void __mutex_fastpath_lock(atomic_t *v,
21 void (*fail_fn)(atomic_t *))
22 {
23 asm_volatile_goto(LOCK_PREFIX " decl %0\n"
24 " jns %l[exit]\n"
25 : : "m" (v->counter)
26 : "memory", "cc"
27 : exit);
28 fail_fn(v);
29 exit:
30 return;
31 }
字符串这里的关键是dec(decl)操作之前的前缀(prefix_PREFIX)。在x86上,prefix表示 * 原子性 ,并且始终表示完全内存屏障*。
dec
decl
mhd8tkvw2#
实际上,互斥锁需要一些内存同步。重要的是如何在没有忙碌自旋锁的情况下等待互斥锁被解锁(由其他线程解锁)(特别是,因为您不希望等待线程占用大量CPU)。阅读futex(7)。与clone(2)一样,futex(2)系统调用仅对线程库的 * 实现者 * 有用。顺便说一句,GNU libc和musl-libc都是POSIX线程的free software实现。如果你想了解细节,请研究它们的源代码。
z9gpfhce3#
这个答案有两个问题:(1)它是特定于x86的,(2)它已经过时了(这将是Linux内核中的常见情况,特别是在八年之后)。当前代码如下:这保证只提供获取语义,而不是一个完整的屏障。是的,这确实在x86上提供了一个完整的屏障,但这是一个实现的意外。这个完整的屏障绝对不能在所有架构中得到保证。
3条答案
按热度按时间s2j5cfk01#
Robert Love的答案适用于 * 任何领域 * 的互斥。
你提到的Linux内核中的实现使用
__mutex_fastpath_lock
,它完成了大部分工作,通常使用汇编代码实现。例如,在x86_64上,它的实现可以是:字符串
这里的关键是
dec
(decl
)操作之前的前缀(prefix_PREFIX)。在x86上,prefix表示 * 原子性 ,并且始终表示完全内存屏障*。mhd8tkvw2#
实际上,互斥锁需要一些内存同步。重要的是如何在没有忙碌自旋锁的情况下等待互斥锁被解锁(由其他线程解锁)(特别是,因为您不希望等待线程占用大量CPU)。阅读futex(7)。与clone(2)一样,futex(2)系统调用仅对线程库的 * 实现者 * 有用。
顺便说一句,GNU libc和musl-libc都是POSIX线程的free software实现。如果你想了解细节,请研究它们的源代码。
z9gpfhce3#
这个答案有两个问题:(1)它是特定于x86的,(2)它已经过时了(这将是Linux内核中的常见情况,特别是在八年之后)。
当前代码如下:
这保证只提供获取语义,而不是一个完整的屏障。是的,这确实在x86上提供了一个完整的屏障,但这是一个实现的意外。这个完整的屏障绝对不能在所有架构中得到保证。