1
volatile int x;

# thread 1
x = 10;  # 1
x += 1;  # 2a, 2b

# thread 2
x = 20   # 3

In the example code, 2 might be interleaved to a read operation 2a and an update operation 2b. In the case 1 - 2a - 3 - 2b, 2a first gets the value of x, which is 10, from the shared memory. Then 3 assigns 20 to x and writes into the shared memory immediately. For the next step 2b, will the thread memory that stores the variable x be forced to refresh due to the volatile keyword, which means the memory is updated to 20 and the result is 21? Or it still uses the previous value 10 and the result is 11?

Many thanks in advance!

chaos
  • 338
  • 4
  • 16
  • If the two blocks of code are in different threads, I don't know how you can make any assumptions about what's going to happen when, and I don't think that the volatile keyword really helps. It might change the behavior, but I can't see how it will make it any more predictable. This is why you need critical sections around such code...so that you can predict what will happen when. - what is the point of this question? – CryptoFool Apr 07 '21 at 02:17
  • I presume it is the same as any other read then write call, however, it makes little difference to you because `1 - 3 - 2a - 2b` should give the same results as `1 - 2a - 3 - 2b`, the window is just far smaller for your scenario of an update happening between 2a and 2b. – sorifiend Apr 07 '21 at 02:24
  • @sorifiend Thank you so much for you reply. I understand different cases can give the same result. This is a school work and I need to analysis different interleaving cases and their results. Back to my question, if it does refresh the memory, does it mean the `2a` read operation is run again after the memory is updated, and the interleaving cases become `1 - 2a - 3 - 2a - 2b`? – chaos Apr 07 '21 at 02:33
  • No, that would not happen. A volatile variable simply blocks reading if a write action is already occurring, so if a variable has already been read prior then it does not notify anything of changes, so this would never happen `1 - 2a - 3 - 2a - 2b`. Instead, 2a happens either before 3, or it waits for the value to update/write before reading so you would only have one of these two scenarios if the thread events happened to occur at the same time `1 - 3 - 2a - 2b` or `1 - 2a - 3 - 2b` – sorifiend Apr 07 '21 at 02:40
  • @sorifiend Sorry for my poor understanding as English is not my first language. x will be 21 in the end of `1 - 3 - 2a - 2b`. But for `1 - 2a - 3 - 2b` x will be 11, since operation 3 does not notify the change to 2b and 2b still increments 10 by 1. Then how are they returning the same result? – chaos Apr 07 '21 at 02:49
  • 2
    they "return the same result" on your run(s), on your CPU, on your OS, etc etc. `x += 1` is not atomic, that's it. – Eugene Apr 07 '21 at 03:05
  • I don't think you correctly identify what 2a and 2b _are_. Can you state what operations 2a and 2b are? – Sweeper Apr 07 '21 at 03:20
  • @Sweeper Sure, my bad. 2 is the whole instruction `x += 1`. Since it is non-atomic it might be interleaved to two operations. In my understanding, 2a is the reading operation that reads the value from the shared memory to the thread working memory. 2b is the write operation that adds the value (1 in my example) to x and then update it to the shared memory. – chaos Apr 07 '21 at 03:27
  • 3
    Okay, you understand correctly. Why do you think volatile somehow synchronises the thread's working (local) memory with the shared memory? It just ensures that updates to the shared memory is visible to every thread. Here's an [example](https://stackoverflow.com/a/130320/5133585) of correctly using volatile. There are more examples on that page. – Sweeper Apr 07 '21 at 03:39
  • @Sweeper nitpick: "shared memory is visible to every thread", should be: shared variable is visible to every thread _when_ at least one thread sees the written value. – Eugene Apr 07 '21 at 16:19

1 Answers1

1

visibility

volatile guarantees visibility of the value across threads (it also helps in happens-before)

x += 1

This is not a single operation There are no atomicity guarantees in the code code.

AtomicInteger.compareAndSet() and AtomicInteger.incrementAndGet() can be used to ensure the atomicity of the operation.

Assuming these 2 operations are independently managed by 2 different threads, then AtomicInteger can not control the sequence of operations. Then it would require some form of wait notify communication.

Thiyanesh
  • 2,360
  • 1
  • 4
  • 11