我认为我主要理解C ++原子库中各种memory_order
标志的语义。
但是,我对以下情况感到困惑:
假设我们有两个线程 - 线程A,它是一个“主执行”线程,而线程B,它是一个任意线程,它是线程池的一部分,可以在其中调度和运行任务。
如果我使用std::memory_order_acq_rel
执行“读写更新”原子操作,则对布尔变量执行非原子写操作,非原子立即写入其他线程?我认为答案是否定的,除非其他线程也访问执行“读写更新”操作的 atomic 变量。
因此,例如,给定全局std::atomic_flag
变量X
,全局bool
值B和具有成员函数{{的线程池对象THREADPOOL
1}},它将在另一个线程中执行任意函数处理程序:
dispatch
所以在这个例子中,lambda函数内的代码将在不同的线程中执行。该线程是否必须在第一个线程中看到if (!X.test_and_set(std::memory_order_acq_rel)
{
if (SOME_CONDITION) B = true;
THREADPOOL.dispatch([]() {
// This executes in Thread B
if (B) { /* do something */ } // are we guaranteed to see changes to B?
});
}
的(非原子)更新?请注意,第二个线程不访问atomic_flag,所以我的理解是在第二个线程中必须看到对B
的更改 not 。
我的理解在这里是否正确?如果是这样,会使用B
更改吗?
答案 0 :(得分:3)
在YYYY-MM-DD
中正确实现dispatch
方法应该在此方法调用之前提供调用方执行的所有操作之间的THREADPOOL
关系以及由此执行的所有操作函数(在你的情况下为lambda),传递给方法。
因此,执行lambda函数的辅助线程肯定会看到由主线程分配的happens-before
的值。
没有发生 - 在订单之前,保证变量修改的立即可见性的唯一方法是使用B
进行修改和阅读。例如,参见this question。
答案 1 :(得分:2)
没有内存顺序规范使未来的内存访问可见。它们最多会阻止它们在原子访问可见之前变得可见。
如果要确保特定访问权限可见,则必须在该访问权限上强制执行特定的内存排序,或者必须具有使用内存排序的未来访问权限,以确保在要使其可见的访问权限之后对其进行排序
所有原子操作都是原子操作。内存排序只允许您做三件事:
建立与先前操作相关的原子操作的顺序,原子或非原子操作 - 保证此操作在它们之后。
针对未来的操作建立此操作的顺序,无论是否为原子 - 此操作保证在它们之前。
与其他原子操作建立排序。
这些都不能确保未来的非原子操作“很快”发生或在任何特定时间变得可见。