0

我对 boost spinlock 代码有一些疑问:

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_;
};
4

3 回答 3

1
  1. ReadWriteBarrier() 是“内存屏障”(在这种情况下用于读取和写入),是对处理器的特殊指令,以确保导致内存操作的任何指令都已完成(load&store操作 - 或者在例如 x86 处理器中,任何两边都有一个内存操作数的操作)。在这种特殊情况下,在我们继续之前确保 InterlockedExchange(&v_,1) 已完成。

  2. 因为 anInterlockedExchange效率会降低(与机器中的任何其他内核进行更多交互以确保所有其他处理器内核都“放开”该值 - 这是没有意义的,因为最有可能(在正确工作的代码中)我们只有unlock当我们实际上持有锁,所以没有其他处理器缓存的值与我们正在写入的值不同),并且volatile写入内存也一样好。

于 2013-02-18T09:19:42.603 回答
0

障碍的存在是为了确保内存同步;没有它们,不同的线程可能会以不同的顺序看到内存的修改。

并且InterlockedExchange在第二种情况下不需要,因为我们对先前的值不感兴趣。的作用 InterlockedExchange无疑是设置值并返回之前的值。(为什么v_会是long,当它只能取值0并且1, 超出了我的范围时。)

于 2013-02-18T09:17:32.093 回答
0

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

于 2013-02-18T15:01:14.713 回答