【问题标题】:Read shared data protected by Mutex without locking Mutex在不锁定 Mutex 的情况下读取受 Mutex 保护的共享数据
【发布时间】:2021-01-12 22:29:12
【问题描述】:

鉴于受 Mutex 保护的共享数据。在不需要锁定互斥锁的情况下读取部分共享数据的适当方法是什么?如下例所示,使用 std::atomic_ref 是否合适?

struct A
{
  std::mutex mutex;
  int counter = 0;
  void modify()
  {
    std::lock_guard<std::mutex> guard(mutex);
    // do something with counter
  }
  int getCounter()
  {
    return std::atomic_ref<int>(counter).load();
  }
};

【问题讨论】:

  • 构造一个临时的atomic_ref 绝对没用。你想做什么具体的实际事情?您为什么不想锁定互斥锁,您希望互斥锁用于什么目的?您需要哪些安全保证?
  • 想一想:它可能与在任何地方都不是原子的long long long int 一起工作吗?它显然不会。

标签: c++ thread-safety locking mutex atomic


【解决方案1】:

如果您绕过锁定互斥锁并从共享数据执行原子读取(例如使用std::atomic_ref),那么如果其他线程之一使用非原子访问写入,您的程序将调用undefined behavior

如果所有线程都使用原子操作来访问共享数据,那么就没有未定义的行为。但是,在这种情况下,如果所有访问都是原子的,那么使用互斥锁保护共享数据可能毫无意义。

【讨论】:

  • 感谢您的回答。但是,锁定和解锁互斥体是否意味着原子访问可以看到内存顺序?
  • @hpc64:memory ordering 的概念仅适用于同一线程中的操作。在您的示例中,一个线程使用原子访问,而另一个线程使用互斥锁。您必须对共享数据进行所有访问,或者必须使用某种形式的线程同步(例如互斥锁)。否则你将有未定义的行为,除非所有线程对共享数据的所有访问都是只读的。
  • @Andreas_Wenzel:@Andreas_Wenzel:Alok Save 在stackoverflow.com/questions/11172922/… 中的回答意味着互斥锁/解锁会添加栅栏,然后原子访问可以看到这些栅栏。
  • @hpc64:根据您引用的答案,互斥锁/解锁操作不是围栏。只有没有关联内存位置的同步操作才是栅栏。与相关内存位置的同步操作(例如互斥锁/解锁操作和原子操作)是获取/释放“操作”,而不是“栅栏”。因此,互斥锁/解锁操作和原子操作只会影响其他线程的可见性,当两个线程使用锁定/解锁/原子操作修改相同的内存位置时(这不适用于您的情况)。
  • @hpc64:即使所有互斥锁锁定/解锁操作都是获取/释放栅栏,您仍然会遇到这样的问题,即线程 A 在锁定互斥锁后对共享数据执行非原子写入,线程 B 可以从共享数据中执行原子读取。由于线程 A 的写入是非原子的,因此在线程 B 的原子读取时,共享数据可能处于不一致状态,因为线程 A 尚未完成其写入操作。 [在下一条评论中继续]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-06
  • 1970-01-01
  • 1970-01-01
  • 2018-03-21
  • 1970-01-01
相关资源
最近更新 更多