memory_order_relaxed有哪些用例

mik*_*ong 10 c++ memory-model

C++内存模型具有宽松的原子性,它不会对内存操作进行任何排序保证.除了我在这里找到的C中的邮箱示例:

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1525.htm

基于本文中的激励示例:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2153.pdf

我很好奇这种同步机制的其他用例.

jac*_*bsa 9

我在工作中经常看到的一个简单例子是统计计数器.如果要计算事件发生的次数,但除了使增量安全之外不需要跨线程的任何类型的同步,使用 memory_order_relaxed是有意义的.

static std::atomic<size_t> g_event_count_;

void HandleEvent() {
  // Increment the global count. This operation is safe and correct even
  // if there are other threads concurrently running HandleEvent or
  // PrintStats.
  g_event_count_.fetch_add(1, std::memory_order_relaxed);

  [...]
}

void PrintStats() {
  // Snapshot the "current" value of the counter. "Current" is in scare
  // quotes because the value may change while this function is running.
  // But unlike a plain old size_t, reading from std::atomic<size_t> is
  // safe.
  const size_t event_count =
      g_event_count_.load(std::memory_order_relaxed);

  // Use event_count in a report.
  [...]
}
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,都不需要使用更强的内存顺序.在某些平台上,这样做会对性能产生负面影响.

  • 这对我来说似乎很好,但是你必须非常小心,不要尝试使用该值进行同步.例如,如果你计算一个结构然后尝试将`std :: atomic <Struct*>`与`std :: memory_order_relaxed`一起使用,你将会遇到一个糟糕的时间,因为你还没有确保其他线程在写入设置指针之前查看初始化结构的写入. (3认同)
  • 好的,所以您有自动递增计数器的编写器。但最终你会想在某个地方读取计数器。就像您的示例中的 PrintStats() 一样。那么,这是否只适用于计数增量不一定必须立即传播的情况?当您使用 std::memory_order_relaxed 读取计数器时,您是否可能读取过时的 g_event_count ? (2认同)
  • 不,这会由于[数据竞争](https://en.cppreference.com/w/cpp/language/memory_model#Threads_and_data_races)而导致未定义的行为。基于编译器实际生成的代码的可能结果是丢失增量,但理论上任何事情都可能发生。 (2认同)