2013-02-18 43 views
0

我有升压自旋锁码的一些问题:约自旋锁

class spinlock 
{ 
public: 
    spinlock() 
     : v_(0) 
    { 
    } 

    bool try_lock() 
    { 
     long r = InterlockedExchange(&v_, 1); 
     _ReadWriteBarrier();  // 1. what this mean    
     return r == 0; 
    } 

    void lock() 
    { 
     for (unsigned k = 0; !try_lock(); ++k) 
     { 
      yield(k); 
     } 
    } 

    void unlock() 
    { 

     _ReadWriteBarrier();      
     *const_cast<long volatile*>(&v_) = 0; 
     // 2. Why don't need to use InterlockedExchange(&v_, 0); 
    } 

private: 
    long v_; 
}; 
+0

好,开锁是无条件的... – 2013-02-18 09:17:18

+0

@KerrekSB此外,先验的,如果你调用'unlock',你有锁,'v_'只能是'1'。 – 2013-02-18 09:18:48

回答

1
  1. 一个ReadWriteBarrier()是一个“记忆障碍”(在这种情况下读取和写入),一个特殊的指令给处理器以确保导致存储器操作的任何指令已经完成(load & store操作 - 或在例如x86处理器,其在每一侧有一个存储器的操作数的任何opertion)。在这种情况下,要确保InterlockedExchange(&v_,1)已经完成,然后再继续。

  2. 因为一个InterlockedExchange将是效率较低(需要更多的互动与机器的任何其他内核,以确保其他所有的处理器内核都“放手”的价值 - 这是没有意义的,因为最有可能(在正常工作代码)我们只unlock如果我们实际持有的锁,所以没有其他的处理器将有不同的值比缓存我们写什么了反正),和volatile写入到内存会一样好。

+0

我以为InterlockedExchange是一个完整的读/写屏障? – ronag 2013-02-18 09:20:50

+0

既然你提到x86--不是x86强烈的排序,所以内存屏障是隐含的?我相信代码主要在x86上充当*编译器*障碍,没有额外的机器代码。 – 2013-02-18 09:21:13

+0

我不清楚它是否实际上导致了指令: http://msdn.microsoft.com/en-us/library/f20w0x5e%28v=vs.80%29.aspx – 2013-02-18 09:23:43

0

的障碍是有保证的内存同步;没有 他们,不同的线程可能会看到 不同的命令修改内存。

并且InterlockedExchange在第二种情况下不是必需的 ,因为我们对先前的值不感兴趣。的 InterlockedExchange作用是无疑要设置的值,并返回 以前的值。 (为什么v_long,何时能 只能采取价值01,是超越我。)

+0

如果'InterlockedExchange'只存在'long',该怎么办? – 2013-02-18 09:18:17

+0

那么图书馆的作者不是很好。事实上,我预计会有相反的结果:'InterlockedExchange'需要一个可以自动访问的类型。在我工作的很多平台上,“长”不能自动访问。 (在某些情况下,没有比'char'更大的原子地访问。) – 2013-02-18 09:48:22

+0

这是Windows,对不对?我不太了解它,但我认为他们会选择一种原子的类型(可能称为“LONG”或“ZKLNGSZINT”或其他方便的东西)。 – 2013-02-18 09:59:40

0

有三个问题与原子访问变量。首先,确保在读或写值的过程中没有线程切换;如果发生这种情况,称为“撕裂”;第二个线程可以看到一个部分写入的值,这通常是无意义的。其次,确保所有处理器都能看到正在写入的变化,或者处理器读取值可以看到以前对该值的任何更改;这被称为“缓存一致性”。第三,确保编译器不会将代码跨读取或写入;这被称为“代码运动”。 InterlockedExchange做前两个;虽然MSDN文档相当混乱,但_ReadWriteBarrier做了第三个,也可能是第二个。