Fil*_*ipp 7 c++ multithreading c++11 relaxed-atomics
在一个线程内,steady_clock::now()保证返回单调递增的值。这如何与多线程观察到的内存排序和读取交互?
atomic<int> arg{0};
steady_clock::time_point a, b, c, d;
int e;
thread t1([&](){
a = steady_clock::now();
arg.store(1, memory_order_release);
b = steady_clock::now();
});
thread t2([&](){
c = steady_clock::now();
e = arg.load(memory_order_acquire);
d = steady_clock::now();
});
t1.join();
t2.join()
assert(a <= b);
assert(c <= d);
Run Code Online (Sandbox Code Playgroud)
这是重要的一点:
if (e) {
assert(a <= d);
} else {
assert(c <= b);
}
Run Code Online (Sandbox Code Playgroud)
这些断言会失败吗?或者我对获取释放内存顺序有什么误解?
以下主要是对我的代码示例的解释和详细说明。
线程t1写入原子arg。它也记录在当前时间之前,并在写入之后a和b分别。steady_clock保证a <= b。
线程t2从原子中读取arg并保存读入的值e。它也记录在当前时间之前和在读之后c和d分别。steady_clock保证c <= d。
然后连接两个线程。此时e可能是0或1。
如果e是0,则t2在t1写入之前读取该值。这是否也意味着c = now()int2发生在b = now()in之前t1?
如果e是1那么t1写的值之前t2读取它。这是否也意味着a = now()int1发生在d = now()in之前t2?
以下是一些现有问题,但无法回答我的问题:
即使使用多核上下文,是否有任何 std::chrono 线程安全保证?
我不是在问是否now()是线程安全的。我知道它是。
这个更接近,但该示例使用mutex. 我可以对比 弱的内存排序做出相同的假设seq_cst吗?
不幸的是,这个问题不完整。获取和释放内存顺序可防止仅在一个方向上重新排序。考虑t1:
a = steady_clock::now();
arg.store(1, memory_order_release);
b = steady_clock::now();
Run Code Online (Sandbox Code Playgroud)
a确实之前就被分配了arg.store。但编译器也可以自由地将分配重新排序为b之前发生的事情。
同样,在t2:
c = steady_clock::now();
e = arg.load(memory_order_acquire);
d = steady_clock::now();
Run Code Online (Sandbox Code Playgroud)
d确实在 后被分配arg.load。但编译器也可以自由地将分配重新排序为c之后发生。
因此assert(c <= b)可能会失败。
但有一点需要注意。steady_clock::now()仅当已知没有可观察到的影响时,这才是正确的。然而,在我查看其实现的平台上,这会导致调用一些不透明的库函数。编译器必须假设此类调用可能会产生可观察到的效果(例如修改易失性变量或终止程序),因此不会对调用重新排序。
如果重要断言仅包含以下内容,则该问题是有效的
if (e) { assert (a <= d); }
Run Code Online (Sandbox Code Playgroud)
或者如果两个内存顺序都是acq_relor seq_cst。
因此,考虑到内存顺序已更正或仅在 时检查断言e != 0,我可以确定相关调用steady_clock::now()实际上以正确的顺序发生,即使跨线程也是如此。
t1但这是否也意味着返回的值与和 之间的顺序一致t2,而不仅仅是在t1和t2之间独立?
我不知道,这就是为什么我不会接受这个答案。