假设一个有两个线程(A和B)的程序正在linux上运行。
int global = 0;
void thread_A(void) {
atomic_store(&global, 1);
udp_send_to_CX();
}
void thread_B(void) {
block_until_udp_recv_from_CX();
int local = atomic_load(&global);
assert(local == 1);
}
线程A发送UDP数据包到另一台计算机CX。收到数据包后,CX将发送一个UDP数据包,该数据包将由线程B接收。CX将不会发送UDP数据包,直到它收到线程A发送的数据包。
在发送UDP数据包之前,线程A将值1存储在全局变量中。
在接收到UDP数据包之后,线程B读取全局变量的值。
我的问题是:
线程B中的Assert是否保证成功。
也就是说,在C++标准的意义上,线程A中的存储是否发生在线程B中的加载之前。
请注意,我们不能对线程A和线程B运行的机器做任何假设。线程A发送的UDP数据包可能通过与线程B中用于接收UDP数据包的链路不同的链路发送。
线程A和B也可能使用不同的套接字来发送和接收分组。
编辑:对以下一些评论和答案的澄清:
例如,如果在linux内核中有一个全局原子计数器,它在发送数据包之前和接收数据包之后立即以获取-释放顺序递增,那么问题的答案将是“是的,Assert总是成功”。例如,send
和recv
系统调用可以实现如下:
int network_counter = 0;
int send(...) {
atomic_inc(&network_counter, 1, acquire_release);
...
}
int recv(...) {
...
atomic_inc(&network_counter, 1, acquire_release);
}
对于任何一个被接受的答案,它都必须解释是否有这样一种机制来确保所有网络操作都有一个特定的时间轴,这个问题特别是关于linux内核的。
(我不相信有这样的计数器,如果有,我怀疑它将是链路本地的。这就是为什么我指定系统中可能有多个链路。)
1条答案
按热度按时间iih3973s1#
原子对象给予你的只是其他执行线程会看到原子对象的旧值或新值,但从来不会看到一些中间表示。
原子性没有指定***何时***对象的新值可被其他执行线程观察到。为此,您需要根据定义的内存模型进行同步。