下面我有一些锁的实现。
如果
m_counter != -1
,则锁可用。如果此条件成立,则增加 m_counter
。
是否可以原子地/CAS 实现
!=
和 ++
并使用获取-释放语义(而不是顺序一致)来提高性能?
#include <atomic>
struct Lock
{
void take_lock()
{
while(true)
{
////////////////////////////////////////////////////////////
// Perform this commented-section atomically and using acquire-release semantics?
if(-1 != m_counter)
{
++m_counter;
////////////////////////////////////////////////////////////
return;
}
while(-1 == m_counter.load(std::memory_order_relaxed))
{
}
}
}
std::atomic<int8_t> m_counter{0};
};
使用原子时,可以选择“无锁编程”。这看起来很简单,但有很多微妙的陷阱。例如,将
int8_t
与 std::atomic
一起使用是个坏主意,因为它可能会因多种原因而变慢(int8_t
是自行播种的,这也大大增加了“错误共享”的危险)。
在您的情况下,这可能看起来像这样:
struct Lock
{
void take_lock()
{
auto original = m_counter.load();
int newValue;
do {
while(original == -1) {
original = m_counter.load();
}
newValue = original + 1;
} while (!m_counter.compare_exchange_strong(original, newValue));
}
std::atomic<int> m_counter{0};
};
https://godbolt.org/z/s5joW5Gzc
有关更多详细信息,请参阅 Herb Sutter 的 cppcon 演讲 “无锁编程(或杂耍剃刀刀片)”(请注意,标题表明需要掌握)(第二部分)。