Jay*_*y D 5 c c++ assembly pointers visual-studio-2008
我想在我的C/C++程序中使用"_test_and_set lock"汇编语言实现和原子交换汇编指令.
class LockImpl
{
public:
static void lockResource(DWORD resourceLock )
{
__asm
{
InUseLoop: mov eax, 0;0=In Use
xchg eax, resourceLock
cmp eax, 0
je InUseLoop
}
}
static void unLockResource(DWORD resourceLock )
{
__asm
{
mov resourceLock , 1
}
}
};
Run Code Online (Sandbox Code Playgroud)
这有效,但这里有一个错误.
问题是我想传递DWORD*resourceLock而不是DWORD resourceLock.
所以问题是如何将指针从C/C++传递到程序集并将其取回.?
提前致谢.
问候,-Jay.
PS这样做是为了避免用户空间和内核空间之间的上下文切换.
如果您是为Windows编写的,则应认真考虑使用临界区对象.关键部分API函数经过优化,除非确实需要,否则它们不会转换到内核模式,因此无争用的正常情况下开销很小.
你的旋转锁定的最大问题是,如果你在一个单独的CPU系统而你正在等待锁定,那么你正在使用所有的循环,而持有锁定的任何东西都不会有机会运行直到你的时间片结束,内核抢占你的线程.
使用临界区比尝试滚动自己的用户模式自旋锁更成功.
问题中原始版本的主要问题是它需要使用寄存器间接寻址并采用引用(或指针参数)而不是锁定 DWORD 的按值参数。
这是 Visual C++ 的可行解决方案。编辑: 我已经与作者离线合作,我们已经验证了这个答案中的代码在他的测试工具中正确工作。
但如果您使用的是 Windows,则确实应该使用 Interlocked API(即 InterlockedExchange)。
编辑:正如 CAF 所指出的,lock xchg
不需要,因为xchg
会自动断言 BusLock。
我还添加了一个更快的版本,它在尝试执行xchg
. 这显着减少了内存接口上的总线锁争用。通过对长时间持有的锁进行退避(让出然后睡眠),可以大大加快该算法的速度(在有争议的多线程情况下)。对于单线程 CPU 的情况,使用在持有锁上立即休眠的操作系统锁将是最快的。
class LockImpl
{
// This is a simple SpinLock
// 0 - in use / busy
// 1 - free / available
public:
static void lockResource(volatile DWORD &resourceLock )
{
__asm
{
mov ebx, resourceLock
InUseLoop:
mov eax, 0 ;0=In Use
xchg eax, [ebx]
cmp eax, 0
je InUseLoop
}
}
static void lockResource_FasterVersion(DWORD &resourceLock )
{
__asm
{
mov ebx, resourceLock
InUseLoop:
mov eax, [ebx] ;// Read without BusLock
cmp eax, 0
je InUseLoop ;// Retry Read if Busy
mov eax, 0
xchg eax, [ebx] ;// XCHG with BusLock
cmp eax, 0
je InUseLoop ;// Retry if Busy
}
}
static void unLockResource(volatile DWORD &resourceLock)
{
__asm
{
mov ebx, resourceLock
mov [ebx], 1
}
}
};
// A little testing code here
volatile DWORD aaa=1;
void test()
{
LockImpl::lockResource(aaa);
LockImpl::unLockResource(aaa);
}
Run Code Online (Sandbox Code Playgroud)