【问题标题】:Atomic load and store with memory order relaxed放宽内存顺序的原子加载和存储
【发布时间】:2018-09-13 15:45:28
【问题描述】:

在我阅读的所有内容中,我都看到强烈建议不要使用宽松的内存顺序,我想知道以下代码是否是可以使用的异常之一,或者我没有看到任何后果。

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 会将更改传播到其他线程?

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

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

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

【问题讨论】:

  • 这只是我的看法:是的,这很好,你的分析是对的。
  • 恕我直言,我被告知 memory_order_release 仅在与 memory_order_aquire 操作(不存在)结合使用时才有效,所以它不是没用吗?

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


【解决方案1】:

据我所知,我什至不能保证我会得到那个值,只是我会得到一个在某个时间点存储在那里的值,但我总是可以得到 nullptr。

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

在实践中似乎有效,我可以期望它在某些情况/平台上失败(总是检索 nullptr)吗?

我不知道。

我可以调整存储操作中的内存顺序来解决这个问题吗?例如memory_order_release 会将更改传播到另一个线程?

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

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

【讨论】:

  • "同一个线程随后无法观察到先前的值" 请注意,这与非易失性 Java 引用不同,后者可能会因编译器优化而触发(如果不同的读取以不同的方式优化) )
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-11
  • 2016-08-17
  • 1970-01-01
  • 2021-08-27
相关资源
最近更新 更多