将指针从C传递到程序集

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这样做是为了避免用户空间和内核空间之间的上下文切换.

Gre*_*ill 6

如果您是为Windows编写的,则应认真考虑使用临界区对象.关键部分API函数经过优化,除非确实需要,否则它们不会转换到内核模式,因此无争用的正常情况下开销很小.

你的旋转锁定的最大问题是,如果你在一个单独的CPU系统而你正在等待锁定,那么你正在使用所有的循环,而持有锁定的任何东西都不会有机会运行直到你的时间片结束,内核抢占你的线程.

使用临界区比尝试滚动自己的用户模式自旋锁更成功.

  • 编写程序集不会有助于实现可移植性.如果您想要可移植的关键部分,请编写中性API代码.考虑提升同步:http://www.boost.org/doc/libs/1_41_0/doc/html/thread/synchronization.html (9认同)
  • 我投票给他的原因很简单,因为它没有回答问题.这个问题是有效的,对它的回答很高兴. (2认同)

Adi*_*sak 1

问题中原始版本的主要问题是它需要使用寄存器间接寻址并采用引用(或指针参数)而不是锁定 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)