对于等待工作线程的主机线程,我应该使用哪种内存顺序?

Which Memory Order Should I use for a Host Thread waiting on Worker Threads?

我有代码可以将任务分派给 asio io_service 对象进行远程处理。据我所知,代码运行正确,但不幸的是,我对内存排序知之甚少,而且我不确定在检查原子标志以确保最佳性能时应该使用哪些内存顺序。

//boost::asio::io_service;
//^^ Declared outside this scope
std::vector<std::atomic_bool> flags(num_of_threads, false);
//std::vector<std::thread> threads(num_of_threads);
//^^ Declared outside this scope, all of them simply call the run() method on io_service

for(int i = 0; i < num_of_threads; i++) {
    io_service.post([&, i]{
        /*...*/
        flags[i].store(true, /*[[[1]]]*/);
    });
}

for(std::atomic_bool & atm_bool : flags) while(!atm_bool.load(/*[[[2]]]*/)) std::this_thread::yield();

基本上,我想知道的是,我应该用什么代替 [[[1]]][[[2]]]

如果有帮助,代码在功能上类似于以下内容:

std::vector<std::thread> threads;
for(int i = 0; i < num_of_threads; i++) threads.emplace_back([]{/*...*/});
for(std::thread & thread : threads) thread.join();

除了我的代码使线程在外部线程池中保持活动状态并向它们分派任务。

您想在设置标志的线程和看到它已设置的线程之间建立先发生 关系。这意味着一旦线程看到标志被设置,它也会看到另一个线程在设置它之前所做的一切的效果(否则不能保证)。

这可以使用发布-获取语义来完成:

flags[i].store(true, std::memory_order_release);
// ...
while (!atm_bool.load(std::memory_order_acquire)) ...

请注意,在这种情况下,使用阻塞 OS 级别的信号量可能比在标志数组上旋转等待更干净。如果做不到这一点,旋转完成任务的数量而不是为每个任务检查一组标志仍然会更有效。