Is the lock statement around several statements a guarantee that all changes will be visible to other threads (provided that they enter the same mutex)?

If you have multiple assignments of common variables within one blocking lock block, does this necessarily mean that all these changes are immediately visible to other threads potentially working on other processors when they enter the lock operator on one object - or are there no such guarantees?

Many examples show that a single โ€œsetโ€ or โ€œgetโ€ a shared variable and describes memory barriers in detail, but what happens if a more complex set of statements is inside? Potentially even function calls that do other things?

Something like that:

lock(sharedObject) { x = 10; y = 20; z = a + 10; } 

If this code runs on a different thread that might be running on a different processor, does it make any guarantees regarding the "visibility" of the change?

 lock (sharedObject) { if (y == 10) { // Do something. } } 

If the answer is no - maybe an explanation , when , can these changes become visible?

+4
source share
2 answers

Blocking lock includes a memory intake at the beginning and at the end (beginning and end of the block). This ensures that any changes in memory will be visible to other kernels (for example, other threads running on other kernels). In your example, changes in x, y, z in your first block block will be visible to any other threads. โ€œVisibleโ€ means that any values โ€‹โ€‹stored in the register will be flushed to memory, and any memory cached in the CPU cache will be flushed to physical memory. ECMA 334 indicates that the blocking block is a block surrounded by Monitor.Enter and Monitor.Exit. In addition, ECMA 335 states in detail that Monitor.Enter "implicitly performs a volatile read operation ..." and "Monitor.Exit" implicitly performs a volatile write operation. This means that modifications will not be visible to other kernels / threads until the end of the blocking block (after Monitor.Exit), but if all your access to these variables is protected by a lock, in any case, simultaneous access to the specified variables in different kernels / there will be no flows.

This actually means that any variables protected by the lock statement do not have to be declared mutable so that their changes are visible to other threads.

Since the sample code contains only an operation that relies on one general atomic operation (reading and writing a single value in y), you can get the same results:

 try { x = 10; y = 20; Thread.VolatileWrite(ref z, a + 10); } 

and

 if(y == 10) { // ... } 

The first block guarantees that the entry in x will be visible before the entry in y, and the entry in y will be visible before the entry in z. It also ensures that if entries in x or y were cached in the CPU cache, that cache would be flushed to physical memory (and thus visible to any other thread) immediately after the call to VolatileWrite.

If in the if(y == 10) block if(y == 10) you are doing something with x and y , you should return to using the lock keyword.

In addition, the following would be identical:

 try { x = 10; y = 20; Thread.MemoryBarrier(); z = a + 10; } 
+4
source

Forgive me if I do not understand your question (very possibly); but I think you are working in a confusing combination of synchronization and visibility concepts.

The whole point of a mutex ("mutual exclusion") is to ensure that two blocks of code are not executed simultaneously. So, in your example, the first block:

 lock(sharedObject) { x = 10; y = 20; z = a + 10; } 

... and the second block:

 lock (sharedObject) { if (y == 10) { // Do something. } } 

... will never be executed at the same time . This lock keyword guarantees you.

Therefore, whenever your code enters the second block, the variables x , y and z must be in a state that is consistent with the full execution of the first. (It is assumed that wherever you access these variables, you lock on sharedObject in the same way as in these fragments.)

This means that the โ€œvisibilityโ€ of intermediate changes in the first block is not related to the perspective of the second, because there will never be time when a change in the value of x occurs, but not y or z .

+1
source

All Articles