网络通信是否会创建 C++11 意义上的happens-before关系?

Muh*_*rma 5 c++ linux networking multithreading udp

假设一个有两个线程(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);
}
Run Code Online (Sandbox Code Playgroud)

线程A向另一台计算机CX发送UDP数据包。收到数据包后,CX 将发送一个 UDP 数据包,该数据包将由线程 B 接收。CX 直到收到线程 A 发送的数据包后才会发送 UDP 数据包。

在发送UDP数据包之前,线程A将值1存储在全局变量中。

线程B收到UDP包后,读取全局变量的值。

我的问题是:

线程 B 中的断言是否保证成功。

也就是说,从 C++ 标准的意义上来说,线程 A 中的存储是否发生在线程 B 中的加载之前。

请注意,我们无法对运行线程 A 和线程 B 的机器做出任何假设。线程 A 发送的 UDP 数据包可能通过与线程 B 中用于接收 UDP 数据包的链路不同的链路发送。

线程 A 和 B 也可能使用不同的套接字来发送和接收数据包。

编辑:针对以下一些评论和答案进行澄清:

例如,如果 Linux 内核中有一个全局原子计数器,在发送数据包之前和接收数据包之后立即通过获取-释放顺序递增,那么问题的答案将是“是的,断言总是成功”。例如send和recv系统调用可以按如下方式实现:

int network_counter = 0;

int send(...) {
    atomic_inc(&network_counter, 1, acquire_release);
    ...
}

int recv(...) {
    ...
    atomic_inc(&network_counter, 1, acquire_release);
}
Run Code Online (Sandbox Code Playgroud)

对于任何要被接受的答案,都必须解释是否存在这样一种机制来确保所有网络操作中存在特定的时间表。这个问题具体是关于linux内核的。

(我不相信有这样的计数器,如果有,那么我怀疑它将是链接本地的。这就是为什么我指定系统中可能有多个链接。)

Sam*_*hik 2

不,该断言不受保证。原子对象给您的只是其他执行线程将看到原子对象的旧值或新值,但永远不会看到某些中间表示。

原子性不指定对象的新值何时可以被其他执行线程观察到。为此,您需要根据定义的内存模型进行同步。