I recently came across the following code while learning about Reentrant Locks in Lock-Free Concurrency:
class ReentrantLock32
{
std::atomic<std::size_t> m_atomic;
std::int32_t m_refCount;
public:
ReentrantLock32() : m_atomic(0), m_refCount(0) {}
void Acquire()
{
std::hash<std::thread::id> hasher;
std::size_t tid = hasher(std::this_thread::get_id());
if (m_atomic.load(std::memory_order_relaxed) != tid)
{
std::size_t unlockValue = 0;
while (!m_atomic.compare_exchange_weak(
unlockValue,
tid,
std::memory_order_relaxed,
std::memory_order_relaxed))
{
unlockValue = 0;
PAUSE();
}
}
++m_refCount;
std::atomic_thread_fence(std::memory_order_acquire);
}
void Release() {
std::atomic_thread_fence(std:memory_order_release);
std::hash<std::thread::id> hasher;
std::size_t tid = hasher(std::this_thread::get_id());
std::size_t actual = m_atomic.load(std::memory_order_relaxed);
assert(actual == tid);
--m_refCount;
if (m_refCount == 0)
{
m_atomic.store(0,std::memory_order_relaxed);
}
}
//...
}
However, it appears that there is a chance of stale data leading to multiple threads acquiring the lock, especially when thread contention is high.
!m_atomic.compare_exchange_weak(
unlockValue,
tid,
std::memory_order_relaxed,
std::memory_order_relaxed)
If two competing threads from different cores attempt to call compare_exchange_weak at the same time, isn't there a chance that the cache coherency protocol for the CPU could fail to invalidate the L1-cache before both threads acquire the lock?