-1

I'd like to know the following:

  1. first thread write atomic variable, for example std::atomic i. Does second thread see the new value on the next load operation?

for example:

std::atomic<uint8_t> i=0;

thr1_func()
{
 i.store(1,std::memory_order_relaxed);//here is first step
}

thr2_func()
{
 while(!i.load(std::memory_order_relaxed);//here is next step
}

Will 'i' variable have new value on first load operation after store operation ? Or may 'i' variable have new value on second or other execution of the command?

thank u in advance.

igor.k
  • 31
  • 6
  • 2
    How can you tell which load operation is the first one after the store operation? – user253751 Mar 18 '20 at 13:34
  • 3
    Can you be extremely precise about what you mean by "after store operation"? How, and again it's important that you be as precise as possible, are you determining that the load is after the store even though they take place in different threads and neither one of them is instantaneous? Are you imagining we check some clock? If so, what clock and when do we check it? The precise details affect the answer you get. (You can say, sensibly, that the load is after the store if the load sees the effects of the store. But then your question makes no sense. So you must mean something else by "after".) – David Schwartz Mar 18 '20 at 15:50
  • @DavidSchwartz Let's say it is `rdtsc` clock. What then? – Maxim Egorushkin Mar 18 '20 at 15:58
  • @MaximEgorushkin That would get a different answer from almost any other way of measuring. I doubt that's what the OP has in mind, but that indicates why it's important to know! – David Schwartz Mar 18 '20 at 16:17
  • @DavidSchwartz. I mean load after store in modification order (4.7.1.5 of standart) by "after store operation". I understand it as one thread make store operation and immideatly after that operation load in other thread occures. – igor.k Mar 18 '20 at 17:10
  • Andreas Wenzel. thr2_func, of course. Thank u. – igor.k Mar 18 '20 at 17:19
  • [tag:store] *A store is a data repository of a set of integrated objects. These objects are modeled using classes defined in database schemas. Data store includes not only data repositories like databases, it is a more general concept that includes also flat files that can store data.* That doesn't seem relevant here. – curiousguy Mar 24 '20 at 18:09

2 Answers2

3

Does second thread see the new value on the next load operation?

If the next load operation happens after store in modification order of that atomic variable then that load read the value from that store.

See std::memory_order for full details:

Modification order

All modifications to any particular atomic variable occur in a total order that is specific to this one atomic variable.

...

  1. Write-read coherence: if a side effect (a write) X on an atomic object M happens-before a value computation (a read) B of M, then the evaluation B shall take its value from X or from a side effect Y that follows X in the modification order of M

Also, in [atomics.order] the standard says that:

Implementations should make atomic stores visible to atomic loads within a reasonable amount of time.

In practice that means that the compiler issues those store and load instructions and then it is up to the hardware to propagate the stored value and make it visible to other CPUs. x86 CPUs use a store buffer, so that the stored new value goes into the store buffer first and becomes visible to other CPUs some (small) time after it left the store buffer. During that time the CPU that stored the value can read it back from the store buffer, but other CPUs cannot.

Some more information: How do I make memory stores in one thread "promptly" visible in other threads?

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • Thank u very much. As far as i understand standart (32.4.12) tells us about "reasonable amount of time" that really isn't detailed. It can be so that thread 2 will make load operation after store operation in thread 1 and the value of variable will be still old. Only atomic read-modify-write operation guarantees to read the last value, doesn't it (32.4.11)?. – igor.k Mar 18 '20 at 17:09
  • @igor.k Normally, one defines the correct ordering and visibility of loads and stores in a non-blocking algorithm using memory orders, and not caring exactly when a store becomes visible (e.g. when this (release) store becomes visible the effects of preceding (non-atomic) stores become visible as well). What is the problem are you trying to solve with a read-modify-write operation? – Maxim Egorushkin Mar 18 '20 at 17:19
  • @igor.k If by "after", you mean after in the sense that the effects are visible because the other operation completed before the next began, then it must see the results. As I understand it, this is the sense of "after" you mean. So if the read doesn't see the results, then by definition it didn't come after. See 4.7.1.4 and 4.7.1.5. – David Schwartz Mar 18 '20 at 17:34
  • I want to understand the mechanism of atomic operations for myself (also for future using). I write tcp server on sockets for receiving and processing telemetric information from remote sensors. I decided to use atomic variable for Unique identification number (UIN) of the sensor. I starting to think about different ways of sensor's behavior. One way is that sensor was connected to server, stored its UIN and immideately lost the connection. So sensor reconnects and wants to find if there is its UIN or not. – igor.k Mar 18 '20 at 17:49
  • If not it will create new object with its UIN and there will be two objects with the same UIN. Of course , it is unreal problem:)) Sensors cannot reconnect so fast. But i decided to understand the mechanism of atomic variables more deeply. Nevethereless, if we decide that such situation is real, i also can use mutex for the UIN variable. Standart (4.7.1.3) guarantees that value of UIN will be the latest version. – igor.k Mar 18 '20 at 17:53
  • @igor.k For generating new UINs you can use an `std::atomic c{1};` and use `unsigned new_UIN = c.fetch_add(1, std::memory_order_relaxed);`, that is guaranteed to not create duplicates. – Maxim Egorushkin Mar 18 '20 at 17:59
  • @Maxim Egorushkin Thank u! – igor.k Mar 18 '20 at 19:06
  • @ David Schwartz Thank u! – igor.k Mar 18 '20 at 19:06
  • Since `load` does not modify the value, it is not related to the modification order. Since all operations are relaxed, the value "will become visible to all other threads in a finite period of time" (this is a quote from the standard), but there are no further guarantees. @igor.k To learn more about the C++ memory model I can recommend this paper which I have co-authored: https://arxiv.org/abs/1803.04432 – mpoeter Mar 18 '20 at 22:15
  • @mpoeter Thank u! – igor.k Mar 19 '20 at 05:51
0

This answer: https://stackoverflow.com/a/60740774/5637254

And if you need to know if load happened after store or store didn't happen yet (i.e. delay load until store) ... you may introduce another variable, or use "invalid value" like zero, and then do "compare_exchange" checking for this invalid value, so load can know if store already happened AND store can check if value was already loaded.

Alex Zaharov
  • 69
  • 1
  • 3