5

Assume a situation where a program with two threads (A and B) is running on 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);
}

Thread A sends a UDP packet to a different computer CX. Upon receiving the packet, CX will send a UDP packet that will be recieved by thread B. CX will not send the UDP packet until after it has received the packet sent by thread A.

Before sending the UDP packet, thread A stores the value 1 in the global variable.

After receiving the UDP packet, thread B reads the value of the global variable.

My question is:

Is the assert in thread B guaranteed to succeed.

That is, does the store in thread A happen before the load in thread B in the sense of the C++ standard.

Note that we cannot make any assumptions regarding the machine on which thread A and thread B are running. The UDP packet sent by thread A might be sent via a different link than then one that is used to receive the UDP packet in thread B.

Threads A and B will also possibly use different sockets to send and receive the packets.

Edit: Clarification in response to some of the comments and answers below:

If there was for example a global atomic counter inside the linux kernel that was incremented with acquire-release orderings immediately before sending a packet and immediately after receiving a packet, then the answer to the question would be "Yes, the assert always succeeds". For example the send and recv syscalls could be implemented as follows:

int network_counter = 0;

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

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

For any answer to be accepted, it will have to explain whether there is such a mechanism that ensures the existence of a certain timeline across all network operations or not. This question is specifically about the linux kernel.

(I do not believe that there is such a counter and if there is, then I suspect it will be link-local. This is why I specified that there might be multiple links in the system.)

MuhKarma
  • 705
  • 7
  • 13
  • There's no UDP in the standart library nor you specify how your code works. Whether assert guaranteed to succeed by the standart depends on your implementation. – ALX23z Apr 01 '23 at 13:39
  • I think, assert is not garanteed. The write need to transfert value into physical, so the read can see previous cached memory of the thread B. We can consider that write+read of global is made in parallel of UDP send+receive, if there nothing to synchronise somewhere we can't know which ends first. Note that if use load(,memory_order_relase)+load(,memory_order_consume) memory access will be safe. – dalfaB Apr 01 '23 at 13:46
  • Related: https://stackoverflow.com/q/49034629 https://stackoverflow.com/q/35837539 https://stackoverflow.com/q/10698253 – Artyer Apr 01 '23 at 13:51
  • If this is supposed to be about C++, why is it written like C?! You could've at least used `std::atomic`. – Red.Wave Apr 01 '23 at 14:50
  • I've added some clarification to the question. ALX23z: This question is specifically about the linux kernel. Please refer to the implementation of UDP operations therein for details about the implemnation. – MuhKarma Apr 01 '23 at 15:18

1 Answers1

2

No, the assert is not guaranteed. All that atomic objects give you is that other execution threads will see either the atomic object's old value or new value, but never some intermediate representation.

Atomicity does not specify when the object's new value is observable by other execution threads. For that, you need synchronization according to a defined memory model.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • I've clarified the question in response to your answer. – MuhKarma Apr 01 '23 at 15:17
  • What about the guarantees on reordering of instructions in current function (by HW or compiler)? The overall answer is great. But details are tricky. – Red.Wave Apr 01 '23 at 15:22
  • Whatever may or may not be the behavior in the current Linux kernel, there are no guarantees, whatsoever, that after installing an updated kernel the behavior remains the same; hence that's why one cannot rely on specific kernel behavior, and can only rely on the behavior specified by the C++ standard. – Sam Varshavchik Apr 01 '23 at 15:24
  • An answer that quotes kernel engineers regarding this question would also be accepted. For example, this question might have been asked on the linux-kernel-mailing-list before and might have gotten an answer. If kernel engineers have said that there is no such guarantee, then that is a sufficient answer. Merely saying that there are no such guarantees without anything to back it up is not very useful since the question is about whether such guarantees exist or not. – MuhKarma Apr 01 '23 at 15:31
  • @MuhKarma , the scope of that guarantee is beyond C++ std spec. That is, you can not get more than this from C++ community. You need ask kernel experts and see if there is any std behavior defined for linux or any OS in such regards. So, you may need to add some relevant tags. – Red.Wave Apr 01 '23 at 16:10