等待使用std :: atomic标志和std :: condition_variable的工作线程 [英] waiting on worker thread using std::atomic flag and std::condition_variable

查看:101
本文介绍了等待使用std :: atomic标志和std :: condition_variable的工作线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个C ++ 17代码段,线程在该代码段上等待另一个代码到达特定阶段:

Here is a C++17 snippet where on thread waits for another to reach certain stage:

std::condition_variable  cv;
std::atomic<bool>        ready_flag{false};
std::mutex               m;


// thread 1
... // start a thread, then wait for it to reach certain stage
auto lock = std::unique_lock(m);
cv.wait(lock, [&]{ return ready_flag.load(std::memory_order_acquire); });


// thread 2
... // modify state, etc
ready_flag.store(true, std::memory_order_release);
std::lock_guard{m};   // NOTE: this is lock immediately followed by unlock
cv.notify_all();

据我了解,这是使用原子标记和条件变量来实现目标的有效方法.例如,无需在此处使用 std :: memory_order_seq_cst .

As I understand this is a valid way to use atomic flag and condition variable to achieve the goal. For example there is no need to use std::memory_order_seq_cst here.

是否可以进一步放松此代码?例如:

Is it possible to relax this code even further? For example:

  • 也许在 ready_flag.load()
  • 中使用 std :: memory_order_relaxed
  • 可能使用 std :: atomic_thread_fence()而不是 std :: lock_guard {m};

推荐答案

首先:此代码确实有效.调用 notify_one 之前的 lock_guard 可确保等待的线程在唤醒时看到 ready_flag 的正确值,这是否是由于虚假唤醒,或者是由于调用了 notify_one .

Firstly: this code is indeed valid. The lock_guard prior to the notify_one call ensures that the waiting thread will see the correct value of ready_flag when it wakes, whether that is due to a spurious wake, or due to the call to notify_one.

第二:如果仅显示对 ready_flag 的访问权限,则对 atomic 的使用是多余的.在写线程上的 lock_guard 范围内,将写操作移到 ready_flag ,并使用更简单,更常规的模式.

Secondly: if the only accesses to the ready_flag are those shown here, then the use of atomic is overkill. Move the write to ready_flag inside the scope of the lock_guard on the writer thread and use a simpler, more conventional pattern.

如果您坚持使用这种模式,那么是否可以使用 memory_order_relaxed 取决于所需的排序语义.

If you stick with this pattern, then whether or not you can use memory_order_relaxed depends on the ordering semantics you require.

如果设置 ready_flag 的线程也写入其他将由读取器线程读取的对象,那么您需要语义以获得/释放语义,以确保数据是正确可见的:读取器线程可能锁定了互斥锁,并在编写器线程锁定了互斥锁之前看到了 ready_flag 的新值,在这种情况下,互斥锁本身将不提供任何订购保证.

If the thread that sets the ready_flag also writes to other objects which will be read by the reader thread, then you need the acquire/release semantics in order to ensure that the data is correctly visible: the reader thread may lock the mutex and see the new value of ready_flag before the writer thread has locked the mutex, in which case the mutex itself would provide no ordering guarantees.

如果设置 ready_flag 的线程没有触及其他数据,或者该数据受到其他互斥锁或其他同步机制的保护,则可以使用 memory_order_relaxed 随处可见,因为您只关心 ready_flag 本身的值,而不关心其他任何写入的顺序.

If there is no other data touched by the thread that sets the ready_flag, or that data is protected by another mutex or other synchronization mechanism, then you can use memory_order_relaxed everywhere, as it is only the value of ready_flag itself that you care about, and not the ordering of any other writes.

atomic_thread_fence 在任何情况下都无法帮助使用此代码.如果使用条件变量,则需要 lock_guard {m} .

atomic_thread_fence doesn't help with this code under any circumstances. If you are using a condition variable, then the lock_guard{m} is required.

这篇关于等待使用std :: atomic标志和std :: condition_variable的工作线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆