自己动手写自旋锁
自旋锁以其高效闻名。顾名思义,自旋即如果无法成功锁住锁资源则会一直循环尝试锁,这与互斥锁的行为较为不同(互斥锁如果无法锁住则会挂起等待)。但其特性也决定了其使用场景,对于简单几步即可完成对共享资源操作的场景,自旋锁效率将会高于互斥量。
本文给出自旋锁的一种x86平台实现。
其实,gcc在4.1以后的版本就支持了内置的自旋锁实现,而各大类UNIX系统中也提供了pthread_spin_lock这样的自旋锁函数。那么为什么还要自己实现呢?
这是由于一些历史遗留问题和跨平台移植共同导致的结果,例如RHEL5 32位系统,其自带的gcc并不支持自旋锁,也没有pthread_spin_lock,但我们依旧需要使用自旋锁特性,那么只好自己动手丰衣足食了。
闲话少叙,代码奉上:
#define barrier() asm volatile ("": : :"memory")
#define cpu_relax() asm volatile ("pause\n": : :"memory")
static inline unsigned long xchg(void *ptr, unsigned long x)
{
__asm__ __volatile__("xchg %0, %1"
:"=r" (x)
:"m" (*(volatile long *)ptr), "0"(x)
:"memory");
return x;
}
void spin_lock(void *lock)
{
unsigned long *l = (unsigned long *)lock;
while (1) {
if (!xchg(l, 1)) return;
while (*l) cpu_relax();
}
}
void spin_unlock(void *lock)
{
unsigned long *l = (unsigned long *)lock;
barrier();
*l = 0;
}
int spin_trylock(void *lock)
{
return !xchg(lock, 1);
}
可以看到,这里我们使用了内联汇编,且用到了汇编指令pause
。
关于pause
,给出pause
指令的一段解释:
Improves the performance of spin-wait loops. When executing a
“spin-wait loop,” a Pentium 4 or Intel Xeon processor suffers a severe
performance penalty when exiting the loop because it detects a
possible memory order violation. The PAUSE instruction provides a hint
to the processor that the code sequence is a spin-wait loop. The
processor uses this hint to avoid the memory order violation in most
situations, which greatly improves processor performance. For this
reason, it is recommended that a PAUSE instruction be placed in all
spin-wait loops.
大意是说这个指令可以提升自旋等待的性能,这个指令将作为对处理器的一个线索或者暗示(hint
),让处理器尽量避免该指令出现时可能存在的内存乱序存储问题。
同时这个指令也将降低自旋等待时的电力消耗。pause
指令是Pentium 4处理器引入的。
上面的例子中,我们还使用了`volatile`关键字,这个关键字在网上有非常多的文章详细解释,主要是两方面作用:
- 告诉编译器该关键字部分不可以做任何优化
- 使用该关键字的变量每次必须从内存中读取,而不能放在cache或寄存器中备份
感谢阅读!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!