std::vector 更改的跨线程可见性仅与 Win32 事件同步

Cross-thread visibility of changes to std::vector synchronized only with Win32 events

假设我有一个 std::vector<Item> class 成员变量,其中 Item 是一些带有 getter 和 setter 的 class。 它是在一个线程 (#1) 中创建的,但由另一个线程 (#2) 用 push_back 填充。最后它在线程#1 中被读取。对其的访问仅与 Windows event objects 同步。当向量被填满时,事件设置为信号状态。

在这种情况下,我应该注意跨线程可见性问题(获取过时值)吗?如果是,如何避免这些问题?

我建议尽可能使用标准同步原语。

你需要锁定一次,直到向量被填满。例如。线程#2 将等待线程#1 完成。

using Item = int;
std::vector<Item> items;
std::mutex mutex;

// #1
auto t1 = std::thread([&items, &mutex](){
  std::lock_guard<std::mutex> lock(mutex);
  // fill in items...
  // ...
});

// #2
auto t2 = std::thread([&items, &mutex](){
  std::lock_guard<std::mutex> lock(mutex);
  // read...
});

// wait...
t1.join();
t2.join();

如果线程 #1 仅在 #2 发出信号后读取,而 #2 在它发出信号后不写入任何新成员,那么您无需担心。

否则,如果读取和写入可能同时发生,则您没有可见性问题,但您有同步问题。 std::vector 不是线程安全的数据结构,因此如果两个线程同时访问它可能会损坏。要么切换到一个不同的、线程安全的数据结构,要么用独占锁包围你的向量访问。对于标准解决方案,请查看 std::mutex.

Microsoft 表示等待事件对象就足够了。

根据MSDN

The following synchronization functions use the appropriate barriers to ensure memory ordering:

  • Functions that enter or leave critical sections
  • Functions that signal synchronization objects
  • Wait functions
  • Interlocked functions

这意味着如果线程 #1 看到发出信号的事件对象的副作用,它必须看到线程 #2 修改向量的副作用。