Should I buy immediately store storage at boot time?

Suppose we have one simple variable ( std::atomic<int> var ) and 2 threads T1 and T2 , and for T1 we have the following code:

 ... var.store(2, mem_order); ... 

and for T2

 ... var.load(mem_order) ... 

Also suppose that T2 (load) executes 123ns later in time (later in modification order in terms of the C ++ standard) than T1 (store). My understanding of this situation is as follows (for different memory orders):

  • memory_order_seq_cst - T2 Load must load 2 . Thus, it should load the last value (as is the case with RMW operations)
  • memory_order_acquire / memory_order_release / memory_order_relaxed - T2 not required to load 2 , but can load any older value with the only restriction: this value should not be older than the last loaded by this stream, So, for example, var.load returns 0 .

Am I right with my understanding?

Update1:

If I am mistaken in the reasoning, provide the text from the C ++ standard, which confirms it. Not only theoretical considerations about how any architecture can work.

+6
source share
2 answers

They did not find any arguments to prove my understanding is wrong, I think it is right, and my proof is as follows:

memory_order_seq_cst - T2 boot should load 2.

This is correct, because all operations using memory_order_seq_cst should form a single general order for the atomic variable of all memory operations. Excerpt from the standard:

[29.9 / 3] All memory_order_seq_cst must have one common order S in accordance with the order โ€œoccurs beforeโ€ and modifications for all affected locations, so that each memory_order_seq_cst that loads a value from an atomic object M observes one of the following values โ€‹โ€‹<... >

The following question is my question:

memory_order_acquire / memory_order_release / memory_order_relaxed - T2 - is not required to load 2, but can load any old value <...>

I did not find any evidence that could indicate that the download, performed later in the modification order, should see the last value. The only points I found for storage / load operations with any memory order other than memory_order_seq_cst are the following:

[29.3 / 12] Implementations should make atomic storage facilities visible to atomic loads within a reasonable amount of time.

and

[1.10 / 28] The implementation must ensure that the last value (in the order of modification) assigned by atomic or synchronization becomes visible to all other flows over a finite period of time.

Thus, the only guarantee we have is that the written variable will be visible for some time - this is a fairly reasonable guarantee, but this does not mean the immediate visibility of the previous store. And this confirms my second point.

Given that my initial understanding was correct.

+1
source

Am I right with my understanding?

No. You misunderstand memory orders.

suppose T2 (load) executes 123ns later than T1 (store) ...

In this case, T2 will see what T1 does with any type of memory order (moreover, this property is used to read / write any memory area, see, for example, http://www.open-std.org/jtc1/sc22/ wg21 / docs / papers / 2015 / n4431.pdf , 1.10, p. 15). The key word in your phrase is later : it means that someone else forces you to organize these operations.

Memory orders are used for another scenario:

It allows you to perform some operation OP1 in the stream T1 before the storage operation, after which OP2 appears, OP3 enters the stream T2 before loading, OP4 appears after it.

 //T1: //T2: OP1 OP3 var.store(2, mem_order) var.load(mem_order) OP2 OP4 

Suppose that some order between var.store() and var.load() can be observed by threads. What can be guaranteed about cross-threading settings for other operations ?

  • If var.store uses memory_order_release , var.load uses memory_order_acquire and var.store ordered to var.load (i.e. loading returns 2), then the effect of OP1 ordered to OP4 .

For example, if OP1 writes some variable var1, OP4 reads this variable, then you can be sure that OP4 will read what OP1 writes before. This is the most used case.

  1. If both var.store and var.load use memory_order_seq_cst and var.store ordered after var.load (i.e. load returns 0, which was the value of the variable before the repository), then the effect of OP2 ordered after OP3 .

This memory order is required for some complex synchronization schemes.

  1. If either var.store or var.load uses memory_order_relaxed , then with any order var.store and var.load you can guarantee that there is no order of operations with transverse streams.

This memory order is used in case someone else provides the order of operations. For example, if the creation of the T2 stream occurs after var.store in T1 , then OP3 and OP4 ordered after OP1 .

UPDATE : 123 ns later implies *someone else* force ordering , because the computer processor has no idea about universal time, and no operation has an exact moment when it is executed. To measure the time between two operations, you must:

  • Observe the order between the completion of the first operation and the beginning of the countdown on some processor.
  • Observe the order between the beginning and the end of the counter.
  • Observe the order between the start of the end time and the start of the second operation.

Transitively, these steps make order between the first and second.

+4
source

Source: https://habr.com/ru/post/988915/


All Articles