[英]How do I safely write a test and test-and-set (TATAS) spinlock with C++11 for x86(-64)?
我目前正在研究Spinlock类,并试图使其尽可能合理,主要是基于以下建议: https : //software.intel.com/zh-cn/articles/implementing-scalable-atomic-locks-for -多核心Intel的EM64T和-IA32架构
正在进行的工作如下所示:
class Spinlock
{
public:
Spinlock() : m_lock(false) {}
void lock()
{
// heavy test here for the usual uncontested case
bool exp = false;
if (!m_lock.compare_exchange_weak(exp, true, std::memory_order_acquire))
{
int failCount = 0;
for (;;)
{
// processor spin loop hint
_mm_pause();
// spin on mov instead of lock instruction
if (!m_lock.load(std::memory_order_relaxed))
{
// heavy test now that we suspect success
exp = false;
if (m_lock.compare_exchange_weak(exp, true, std::memory_order_acquire))
{
return;
}
}
// backoff (potentially make exponential later)
if (++failCount == SOME_VALUE)
{
// Yield somehow.
failCount = 0;
}
}
}
}
void unlock()
{
m_lock.store(false, std::memory_order_release);
}
std::atomic_bool m_lock;
};
但是,从那里轻松地读取内容似乎可以从理论上允许生成的代码做意外的事情,例如创建死锁: http : //joeduffyblog.com/2009/02/23/the-magical-dueling-deadlocking-spin-locks/
这段代码不应像链接示例那样陷入僵局,因为外部获取应该防止松弛的负载向后移动,但是我实际上并没有处理所有可能存在的代码转换。 我需要什么存储顺序和/或防护来确保此代码安全而不丢失性能? 因为周围的内存顺序过于宽松,退回实现是否有可能比预期的发生更多或更少的频繁(>几次循环)?
在相关说明中,为什么网络上的自旋锁示例对自旋锁使用获取/释放内存顺序而不是顺序一致? 我发现有一条评论说,允许自旋锁发布越过以后的自旋锁获取可能导致问题: http : //preshing.com/20120913/acquire-and-release-semantics/#IDComment721195810
这段代码不应像链接示例那样陷入僵局,因为外部获取应该防止松弛的负载向后移动,但是我实际上并没有处理所有可能存在的代码转换。
获取操作保证编译器和CPU都不会在获取操作之前对后续的读取进行重新排序。
我需要什么存储顺序和/或防护来确保此代码安全而不丢失性能?
您在这里不需要任何额外的同步,您的代码可以完成正确的事情。
为什么网络上的自旋锁示例使用自旋锁的获取/释放内存顺序而不是顺序一致?
因为获取/释放语义足以实现互斥体。 在某些体系结构上,顺序一致性操作比获取/发布更为昂贵。
我不建议您看足够多的atomic <>武器:C ++内存模型和现代硬件 ,它非常详细地介绍了此主题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.