关于旋转锁(spinlock)实现的疑问

疾似云流 2011-05-21 12:40:07
一个简单的spinlock大概是下面这个样子,用InterlockedCompareExchange来不断比较看是否可以进入

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

void Lock()
{
while (::InterlockedCompareExchange(&v_, 1, 0) == 1)
{
_mm_pause(); // 这里可以优化以适应比较激烈的场合
}
}

void UnLock()
{
::InterlockedCompareExchange(&v_, 0, 1);
}

private:
enum {CACHE_SIZE = 64}; // 高速缓存的优化

char padding1[CACHE_SIZE/2];
long v_;
char padding2[CACHE_SIZE/2 - sizeof(long)];
};


这个实现比较容易理解,知道spinlock的概念再翻翻MSDN上InterlockedCompareExchange的API说明就行了。

然后我看到boost里有一个spinlock的实现,代码大致如下:


void yield(unsigned k)
{
if (k < 4)
{
}
else if (k < 16)
{
_mm_pause();
}
else if (k < 32)
{
::Sleep(0);
}
else
{
::Sleep(1);
}
}

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

bool try_lock()
{
long r = InterlockedExchange(&v_, 1);
_ReadWriteBarrier(); // 这个起嘛作用?
return r == 0;
}

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

void unlock()
{
// 这里没有使用Interlocked系列函数,why?
_ReadWriteBarrier();
*const_cast<long volatile*>(&v_) = 0; // const_cast和volatile?
}

private:
long v_;
};


没有使用InterlockedCompareExchange,而是在try_lock里用InterlockedExchange,这个都能理解,不过那个_ReadWriteBarrier是什么意思呢?能用在什么场合?

另外解锁(unlock)的时候也是用的那个_ReadWriteBarrier,没有使用同步函数,最后给锁变量赋值的时候为什么用到const_cast和volatile呢?

求大虾不吝赐教啊……
...全文
396 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
Hisenel 2011-06-30
  • 打赏
  • 举报
回复
关注中
疾似云流 2011-06-18
  • 打赏
  • 举报
回复
内存栅栏和一般的互斥锁(临界区,Mutex等等)有什么区别呢?

或者说在什么样的情况下应该使用Memory Barrier,什么情况下不该用?
ljt3969636 2011-05-21
  • 打赏
  • 举报
回复
_ReadWriteBarrier();

内存栅栏。目前好多处理器都会对指令进行reorder,尤其是intel的处理器,更尤其的是intel的服务器处理器,reorder的一种后果就是你想先写数据再读数据,那么经过处理器reorder可能是先读了数据再写数据。

内存栅栏,这个东西名字很形象,你可以认为在一个“全栅栏”位置前后的读写指令不会被reorder,并且在遇到一个“全栅栏”时之前的读写指令全部会被完成。

对于目前volatile在多线程下的情况,我怕自己表述不清,直接引段文字给您(里面说的多线程情况,我觉得理解为多核心情况更好些~~)

The C and C++ standards do not address multiple threads (or multiple processors), and as such, the usefulness of volatile depends on the compiler and hardware. Although volatile guarantees that the volatile reads and volatile writes will happen in the exact order specified in the source code, the compiler may generate code (or the CPU may re-order execution) such that a volatile read or write is reordered with regard to non-volatile reads or writes, thus limiting its usefulness as an inter-thread flag or mutex. Preventing such is compiler specific, but some compilers, like gcc, will not reorder operations around in-line assembly code with volatile and "memory" tags, like in: asm volatile ("" : : : "memory"); (See more examples in compiler memory barrier). Moreover, you are not guaranteed that volatile reads and writes will be seen in the same order by other processors due to caching, cache coherence protocol and relaxed memory ordering, meaning volatile variables alone may not even work as inter-thread flags or mutexes.
Some languages and compilers may provide sufficient facilities to implement functions which address both the compiler reordering and machine reordering issues. In Java version 1.5 (also known as version 5), the volatile keyword is now guaranteed to prevent certain hardware and compiler re-orderings, as part of the new Java Memory Model. The proposed C++ memory model does not use volatile, instead C++0x will include special atomic types and operations with semantics similar to those of volatile in the Java Memory Model.


贪食蛇男 2011-05-21
  • 打赏
  • 举报
回复
_ReadWriteBarrier,是把之前的读写生效进内存,因为多个线程操作同一个内存地址,可能大家把内存里的数读入寄存器,在寄存器里计算完后再写回内存,这就可能造成读入寄存器里的没有及时写回内存,下一个线程再操作时可能数据不一致,_ReadWriteBarrier强制完成内存读写。
这函数是用来纠正编译器的过度优化。
volatile 关键字也是向编译器建议,不要对此变量的操作使用优化。

5,530

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 模式及实现
社区管理员
  • 模式及实现社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧