原子加载和存储,并简化了存储顺序

时间:2018-09-13 15:45:28

标签: c++ c++11 concurrency memory-model memory-barriers

我在所有阅读的地方都看到强烈建议不要使用宽松的内存顺序,我想知道下面的代码是否是可以工作的例外之一,还是有我看不到的任何后果。

class SessionHolder {
public:

  void set_session(std::shared_ptr<Session> session) {
    std::atomic_store_explicit(&_session, session, std::memory_order_relaxed);
  }

  std::shared_ptr<Session> get_session() const {
    return std::atomic_load_explicit(&_session, std::memory_order_relaxed);
  }

private:

  std::shared_ptr<Session> _session;
};

原则上,当我执行get_session时,无论是会话还是nullptr,我都不会在意哪个会话。但是,如果另一个线程进行存储(这种情况很少发生),我希望最终在合理的延迟内获得该值。

  • 据我了解,甚至不能保证我会得到该值,只是我会得到某个时间点存储在其中的值,但我总能得到nullptr。
  • 在实践中似乎可行,我是否可以指望它在某些情况/特定平台上会失败(总是检索nullptr)?
  • 能否仅在修复存储操作时调整存储顺序?例如memory_order_release会将更改传播到另一个线程吗?

有关如何使用此类的更多上下文:

基本上,我有某种不断产生数据的流。在某个时候,客户端进程可能会连接(开始会话)并开始侦听此数据。生产者线程将连续写入流,如果没有活动会话,则数据将被丢弃,否则将被发送到客户端。当客户端连接时,在某个时间点(不是经常)的另一个线程到达此流并设置会话。

生产者线程必须具有尽可能少的竞争,即使这意味着丢失一些消息。

1 个答案:

答案 0 :(得分:2)

  

据我了解,甚至不能保证我会得到该值,只是我会得到某个时间点存储在其中的值,但我总能得到nullptr。

是的,假设每次对get_session的调用都可能返回空指针,但这不太可能。甚至宽松的内存顺序提供的一种保证是,一旦特定线程观察到一个值,则同一线程随后将无法观察到先前的值。因此,一旦特定线程开始观察到非空指针,则该线程在随后的对get_session的调用中将始终观察到非空指针(假定从未存储空指针)。

  

在实践中似乎可行,我是否可以指望它在某些情况下/平台上会失败(总是检索nullptr)?

不是我所知道的。

  

我可以仅在存储操作中调整存储顺序吗?例如memory_order_release会将更改传播到另一个线程吗?

不。该标准没有提供任何方法来确保线程间通信在任何特定时间内完成。只有实现可以提供这种保证。

最后一个注释:nullptr与“空指针”不同。这是唯一类型的特殊常量,可以将其转换为另一种类型的空指针。