C ++

我正在用c ++编写一个多线程应用程序,其中性能至关重要。 我需要在线程之间复制小结构时使用大量锁定,因为我选择使用自旋锁。

我已经做了一些研究和速度测试,我发现大多数实现大致同样快速:

  • 微软的CRITICAL_SECTION,SpinCount设置为1000,分数约为140个时间单位
  • 使用Microsofts InterlockedCompareExchange实现此算法,得分约95个时间单位
  • 我也尝试过使用类似这段代码的__asm {}来使用一些内联汇编,它的分数大约是70个时间单位, 但我不确定是否已经创建了适当的内存屏障。
  • 编辑:这里给出的时间是两个线程锁定和解锁百万次螺旋锁所花费的时间。

    我知道这并没有太大的区别,但由于自旋锁是一个被广泛使用的对象,人们会认为程序员会以最快的方式达成自旋锁定。 谷歌搜索导致许多不同的方法,但是。 如果使用内联汇编并使用指令CMPXCHG8B而不是比较32位寄存器来实现,我会认为这种上述方法是最快的。 此外,必须考虑内存屏障,这可以通过LOCK CMPXHG8B(我认为?)来完成 ,它保证了内核之间共享内存的“独占权”。 最后(有人建议)对于繁忙的等待应该伴随着NOP:REP ,这将使超线程处理器切换到另一个线程,但我不确定这是否是真的?

    从我对不同自旋锁的性能测试中可以看出,没有太大的差别,但为了纯学术目的,我想知道哪一个最快。 然而,由于我在汇编语言和内存障碍方面的经验非常有限,如果有人能够为我在LOCK CMPXCHG8B中提供的最后一个示例编写汇编代码并在以下模板中使用适当的内存屏障 ,我会很高兴:

    __asm
    {
         spin_lock:
             ;locking code.
         spin_unlock:
             ;unlocking code.
    }
    

    看看这里:使用cmpxchg的x86 spinlock

    感谢Cory Nelson

    __asm{
    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
    }
    

    另有消息称:http://www.geoffchappell.com/studies/windows/km/cpu/cx8.htm

           lock    cmpxchg8b qword ptr [esi]
    is replaceable with the following sequence
    
    try:
            lock    bts dword ptr [edi],0
            jnb     acquired
    wait:
            test    dword ptr [edi],1
            je      try
            pause                   ; if available
            jmp     wait
    
    acquired:
            cmp     eax,[esi]
            jne     fail
            cmp     edx,[esi+4]
            je      exchange
    
    fail:
            mov     eax,[esi]
            mov     edx,[esi+4]
            jmp     done
    
    exchange:
            mov     [esi],ebx
            mov     [esi+4],ecx
    
    done:
            mov     byte ptr [edi],0
    

    这里是关于无锁vs锁实现的讨论:http://newsgroups.derkeiler.com/Archive/Comp/comp.compogramming.threads/2011-10/msg00009.html


    虽然已经有了一个可以接受的答案,但有些东西可能会被用来改善所有答案,从以下英特尔文章中可以看出,以上都是快速锁定实现:

  • 在易失性读取上旋转,而不是原子指令,这可以避免不必要的总线锁定,特别是在高度竞争的锁定上。
  • 对高度争议的锁使用补偿
  • 内联锁,最好是对于内联asm是有害的编译器(基本上MSVC)的内在函数。

  • 维基百科在spinlocks上有一篇很好的文章,这里是x86的实现

    http://en.wikipedia.org/wiki/Spinlock#Example_implementation

    注意它们的实现不使用“lock”前缀,因为它在xchg指令的x86上是冗余的 - 它隐含地具有锁定语义,正如此Stackoverflow讨论中所讨论的:

    在多核x86上,是否需要LOCK作为XCHG的前缀?

    REP:NOP是PAUSE指令的别名,您可以在这里了解更多信息

    x86如何暂停spinlock中的指令工作*和*是否可以在其他场景中使用?

    关于记忆障碍的问题,这里是你可能想知道的一切

    内存障碍:Paul E. McKenney的软件黑客硬件视图

    http://irl.cs.ucla.edu/~yingdi/paperreading/whymb.2010.06.07c.pdf

    链接地址: http://www.djcxy.com/p/64597.html

    上一篇: c++

    下一篇: Call custom ArrayAdapter method from another Activity