Hon*_*gli 37 c concurrency multithreading mutual-exclusion spinlock
我正在使用旋转锁来保护非常小的关键部分.争用情况非常罕见所以自旋锁是比常规的互斥体更合适.
我目前的代码如下,并假设x86和GCC:
volatile int exclusion = 0;
void lock() {
while (__sync_lock_test_and_set(&exclusion, 1)) {
// Do nothing. This GCC builtin instruction
// ensures memory barrier.
}
}
void unlock() {
__sync_synchronize(); // Memory barrier.
exclusion = 0;
}
Run Code Online (Sandbox Code Playgroud)
所以我想知道:
__sync_lock_release.我不是记忆障碍的专家,所以我不确定我是否可以使用它而不是__sync_synchronize.我不在乎在所有有关争.有可能是1,也许2其他线程试图每过一次锁自旋锁天.
sig*_*ice 20
看起来很好.顺便说一句,这是教科书实施,即使在竞争情况下也更有效.
void lock(volatile int *exclusion)
{
while (__sync_lock_test_and_set(exclusion, 1))
while (*exclusion)
;
}
Run Code Online (Sandbox Code Playgroud)
Pee*_*oot 18
所以我想知道:
* Is it correct?
Run Code Online (Sandbox Code Playgroud)
在上面提到的上下文中,我会说是的.
* Is it optimal?
Run Code Online (Sandbox Code Playgroud)
这是一个有问题的问题.通过重新发明轮子,您也在重新发明许多其他实现已经解决的问题
我不希望在你没有尝试访问锁定字的情况下发生故障.
在解锁中使用完整屏障只需要具有释放语义(这就是为什么你要使用__sync_lock_release,这样你就可以在itanium而不是mf上获得st1.rel,或者在powerpc上使用lwsync,...).如果你真的只关心x86或x86_64这里使用的障碍类型并不重要(但是如果你在哪里跳转到intel的itanium用于HP-IPF端口那么你就不会想要这个).
你没有在废物循环之前通常放置的pause()指令.
当有争议的时候,你会想要一些东西,一边是绝望,甚至是一种绝望的愚蠢睡眠.如果你真的需要这个购买的性能,那么futex建议可能是一个很好的建议.如果你需要这个性能,那么你购买的代码就足以维护这段代码,你需要做很多研究.
请注意,有评论说不需要释放障碍.即使在x86上也是如此,因为释放屏障也可以作为编译器的指令,以便不对"屏障"周围的其他内存访问进行混乱.非常像你使用asm("":::"memory")时会得到的结果.
* on compare and swap
Run Code Online (Sandbox Code Playgroud)
在x86上,sync_lock_test_and_set将映射到具有隐含锁定前缀的xchg指令.绝对是最紧凑的生成代码(特别是如果你使用一个字节作为"锁定字"而不是int),但不比使用LOCK CMPXCHG更正确.比较和交换的使用可以用于发烧友algorthims(比如在失败时将第一个"服务员"的元数据的非零指针放入锁定字).