使用CMPXCHG 86自旋锁 [英] x86 spinlock using cmpxchg

查看:638
本文介绍了使用CMPXCHG 86自旋锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是新来使用gcc内联汇编,如果,想知道一个x86多核心机,一个自旋锁(无竞争状态)上可以实现为(使用AT& T语法):


用spin_lock:
MOV EAX 0
锁CMPXCHG 1 [lock_addr]
JNZ用spin_lock
RETspin_unlock:
锁定MOV 0 lock_addr]
RET


解决方案

您有正确的想法,但你的ASM被打破:

CMPXCHG 不能立即数工作,只注册。

锁定不是 MOV 一个有效的preFIX。 MOV 来对齐的地址是在x86原子,所以你不需要锁定反正。

这已经有一段时间,因为我已经使用AT& T公司的语法,希望我记得一切:

 用spin_lock:
xorl%ECX,ECX%
含%ECX
spin_lock_ret​​ry:
xorl%EAX,EAX%
锁; cmpxchgl%ECX(lock_addr)
JNZ spin_lock_ret​​ry
RETspin_unlock:
MOVL $ 0(lock_addr)
RET

注意,GCC有原子内建命令,这样你实际上并不需要使用内联汇编来实现:

 无效用spin_lock(INT * P)
{
    而(!__ sync_bool_compare_and_swap(对,0,1));
}无效spin_unlock(INT挥发性* P)
{
    ASM挥发性(); //作为内存屏障。
    * p值= 0;
}

由于下面博说,锁定指令收取费用:您使用任何人都必须刷新缓存并锁定您的系统的内存总线,它可以是相当昂贵的,如果你有足够的CPU。即使没有多少CPU,它仍然容易,值得各地进行优化:

 无效用spin_lock(INT挥发性* P)
{
    而(!__ sync_bool_compare_and_swap(第0,1))
    {
        而(* p)的_mm_pause();
    }
}

暂停指令是对CPU的超线程性能至关重要的,当你有code的旋转这样的 - 它可以让第二个线程中执行,而第一螺纹在打转。在不支持暂停的CPU,它被视为一个 NOP

I'm new to using gcc inline assembly, and was wondering if, on an x86 multi-core machine, a spinlock (without race conditions) could be implemented as (using AT&T syntax):

spin_lock:
mov 0 eax
lock cmpxchg 1 [lock_addr]
jnz spin_lock
ret

spin_unlock:
lock mov 0 [lock_addr]
ret

解决方案

You have the right idea, but your asm is broken:

cmpxchg can't work with an immediate operand, only registers.

lock is not a valid prefix for mov. mov to an aligned address is atomic on x86, so you don't need lock anyway.

It has been some time since I've used AT&T syntax, hope I remembered everything:

spin_lock:
xorl %ecx, %ecx
incl %ecx
spin_lock_retry:
xorl %eax, %eax
lock; cmpxchgl %ecx, (lock_addr)
jnz spin_lock_retry
ret

spin_unlock:
movl $0 (lock_addr)
ret

Note that GCC has atomic builtins, so you don't actually need to use inline asm to accomplish this:

void spin_lock(int *p)
{
    while(!__sync_bool_compare_and_swap(p, 0, 1));
}

void spin_unlock(int volatile *p)
{
    asm volatile (""); // acts as a memory barrier.
    *p = 0;
}

As Bo says below, locked instructions incur a cost: every one you use must flush your cache and lock your system's memory bus, which can be quite expensive if you've got enough CPUs. Even without many CPUs, it's still easy and worth it to optimize around:

void spin_lock(int volatile *p)
{
    while(!__sync_bool_compare_and_swap(p, 0, 1))
    {
        while(*p) _mm_pause();
    }
}

The pause instruction is vital for performance on HyperThreading CPUs when you've got code that spins like this -- it lets the second thread execute while the first thread is spinning. On CPUs which don't support pause, it is treated as a nop.

这篇关于使用CMPXCHG 86自旋锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆