简体   繁体   English

以下为可重入锁编写的代码是否容易受到指令重新排序错误的影响?

[英]Could the following code written for a Reentrant Lock be susceptible to an instruction reordering error?

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, I'm unsure whether the release fence call doesn't preclude the possibility of later memory operations in the thread preceding it and whether the acquire fence precludes the possibility of earlier memory operation succeeding it.但是,我不确定释放栅栏调用是否不排除在它之前的线程中进行后续 memory 操作的可能性,以及获取栅栏是否排除在它之后进行更早的 memory 操作的可能性。 If they don't, wouldn't it technically be possible that an optimisation could cause the line如果他们不这样做,从技术上讲,优化可能会导致这条线吗?

   if (m_refCount == 0)

to be suceeded by a complete and successful call to Acquire() on the same thread before the call to在调用之前在同一线程上完成并成功调用 Acquire()

     m_atomic.store(0,std::memory_order_relaxed);

in which case the valid incrementation in the reordered Acquire() call would be overwritten by the delayed store() call?在这种情况下,重新排序的 Acquire() 调用中的有效增量将被延迟的 store() 调用覆盖?

When analyzing this code it also occurred to me that there might be stale data issues which lead to duplicate locks which is questioned here .在分析这段代码时,我还想到可能存在导致重复锁的陈旧数据问题,这在此处受到质疑。

There is also another related question to clarify the potential order of memory operations for release fence calls here .还有另一个相关问题来澄清 memory 操作的潜在顺序以释放围栏调用here

That can't happen.那不可能发生。

The situation you mention takes place within a thread.你说的情况发生在线程内。 A variable is always sequentially consistent with itself within a thread.一个变量在一个线程中总是与它自身顺序一致。 (Otherwise it would be impossible to program.) (否则无法编程。)

If, for example, m_atomic.store(0,std::memory_order_relaxed);例如,如果m_atomic.store(0,std::memory_order_relaxed); is stuck in the store buffer, the CPU knows to look there for the load in this line: if (m_atomic.load(std::memory_order_relaxed) != tid)卡在存储缓冲区中,CPU 知道在该行中查找负载: if (m_atomic.load(std::memory_order_relaxed) != tid)

Regardless of how relaxed a variable is, within a thread, optimizations aren't allowed to change the semantics of the source code.无论变量多么宽松,在线程内,优化都不允许更改源代码的语义。 Atomics only exist to provide visibility ordering guarantees to other threads.原子的存在只是为了向其他线程提供可见性排序保证。

BTW, it's not accurate to say this:顺便说一句,这样说是不准确的:

the release fence doesn't preclude the possibility of a later operation in the thread preceding it释放栅栏不排除在它之前的线程中进行后续操作的可能性

According to Jeff Preshing:根据杰夫普雷兴的说法:

A release fence prevents the memory reordering of any read or write which precedes it in program order with any write which follows it in program order.释放栅栏可防止 memory 对按程序顺序在其之前的任何读取或写入与按程序顺序在其之后的任何写入进行重新排序。 https://preshing.com/20130922/acquire-and-release-fences/ https://preshing.com/20130922/acquire-and-release-fences/

This means that in theory C++ acquire/release atomic thread fences are a bit more strict than the common notion of acquire/release memory barriers, by which reordering is allowed 1-way.这意味着理论上 C++ 获取/释放原子线程栅栏比获取/释放 memory 屏障的常见概念更严格,通过后者允许单向重新排序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM