gpt4 book ai didi

c++ - pthread_spinlock 和 boost::smart_ptr::spinlock 之间的区别?

转载 作者:IT王子 更新时间:2023-10-29 00:33:13 25 4
gpt4 key购买 nike

我在boost::smart_ptr中找到了以下自旋锁代码:

bool try_lock()
{
return (__sync_lock_test_and_set(&v_, 1) == 0);
}
void lock()
{
for (unsigned k=0; !try_lock(); ++k)
{
if (k<4)
; // spin
else if (k < 16)
__asm__ __volatile__("pause"); // was ("rep; nop" ::: "memory")
else if (k < 32 || k & 1)
sched_yield();
else
{
struct timespec rqtp;
rqtp.tv_sec = 0;
rqtp.tv_nsec = 100;
nanosleep(&rqtp, 0);
}
}
}
void unlock()
{
__sync_lock_release(&v_);
}

因此,如果我理解正确的话,当锁被争用时,传入线程将呈指数级后退,首先疯狂旋转,然后暂停,然后放弃其时间片的剩余部分,最后在休眠和放弃之间来回切换。

我还找到了 glibc pthread_spinlock 实现,它使用汇编来执行锁。

#define LOCK_PREFIX "lock;" // using an SMP machine

int pthread_spin_lock(pthread_spinlock_t *lock)
{
__asm__ ("\n"
"1:\t" LOCK_PREFIX "decl %0\n\t"
"jne 2f\n\t"
".subsection 1\n\t"
".align 16\n"
"2:\trep; nop\n\t"
"cmpl $0, %0\n\t"
"jg 1b\n\t"
"jmp 2b\n\t"
".previous"
: "=m" (*lock)
: "m" (*lock));

return 0;
}

我承认我对汇编的理解不是很好,所以我不完全理解这里发生了什么。 (有人可以解释一下这是做什么的吗?)

但是,我对 boost 自旋锁和 glibc pthread_spinlock 进行了一些测试,当内核数多于线程数时,boost 代码的性能优于 glibc 代码

另一方面,当线程数多于内核时,glibc 代码会更好

这是为什么?这两种自旋锁实现之间的区别是什么,这使得它们在每种情况下都有不同的表现?

最佳答案

问题中发布的 pthread_spin_lock() 实现是从哪里获得的?它似乎缺少几行重要的代码。

我看到的实现(不是内联汇编 - 它是来自 glibc/nptl/sysdeps/i386/pthread_spin_lock.S 的独立汇编源文件)看起来很相似,但有两个额外的关键说明:

#include <lowlevellock.h>

.globl pthread_spin_lock
.type pthread_spin_lock,@function
.align 16
pthread_spin_lock:
mov 4(%esp), %eax
1: LOCK
decl 0(%eax)
jne 2f
xor %eax, %eax
ret

.align 16
2: rep
nop
cmpl $0, 0(%eax)
jg 1b
jmp 2b
.size pthread_spin_lock,.-pthread_spin_lock

它递减传入参数指向的long,如果结果为零则返回。

否则,结果为非零,这意味着该线程没有获得锁。所以它执行了一个rep nop,相当于pause指令。这是一个“特殊”nop,它向 CPU 提示线程处于自旋状态,并且 cpu 应该以某种方式处理内存排序和/或分支预测,以提高这些情况下的性能(我不假装准确了解芯片外壳下发生的不同情况 - 从软件的角度来看,这与普通的旧 nop 没有区别。

pause 之后,它再次检查该值 - 如果它大于零,则锁未被认领,因此它跳转到函数的顶部并尝试再次认领锁。否则,它会再次跳转到 pause

这个自旋锁和 Boost 版本之间的主要区别在于,这个自旋锁在自旋时不会做任何比 pause 更有趣的事情——没有什么比 sched_yield()纳米 sleep ()。所以线程保持热。我不确定这在你注意到的两种行为中究竟是如何发挥作用的,但是 glibc 代码会更贪婪——如果一个线程在锁上旋转并且有其他线程准备运行但没有可用的核心,旋转线程不会'不会帮助等待的线程获得任何 CPU 时间,而 Boost 版本最终会自动为等待某些关注的线程让路。

关于c++ - pthread_spinlock 和 boost::smart_ptr::spinlock 之间的区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11111720/

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