【发布时间】:2012-06-22 03:03:00
【问题描述】:
我在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 spinlock 和 glibc pthread_spinlock 进行了一些测试,当 内核多于线程时,boost 代码的性能优于 glibc 代码。
另一方面,当线程多于内核时,glibc 代码更好。
这是为什么?这两种自旋锁实现有什么区别,使它们在每种情况下的表现都不同?
【问题讨论】:
-
有趣的是,几年前我进行了类似的测试并得出了相同的结论:当有很多争用时,
pthread_spin_lock比手动自旋锁更有效(来自 boost 的那一行)。
标签: c++ linux performance spinlock