问题描述
这是一个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 :: atomic_thread_fence()
而不是std :: lock_guard {m};
std :: memory_order_relaxed
推荐答案
首先:此代码确实有效.调用 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的工作线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!