In a multi-threaded (Java or .Net) program, can one assume that copying a variable is atomic?

I was worried about the state of the race in the application that I am developing when I was interested about this issue.

Say I have a large array or collection of some kind, managed by one component of my program, let this Monitor component. Its task is to regularly check whether the collection is "dirty", i.e. e. has recently changed, and if so, write the snapshot to disk (this will be the reference point of the application in case of failure) and mark it as clean.

Other components of the same program running in a different thread call the Monitor methods to add data or modify data in the array / collection. These methods mark the collection as dirty.

Now change methods are executed in the threads of other components, right? And if I’m not lucky, they can be called while the picture is being written to disk, change the data that has already been written, set the flag dirty, and the Monitor stream will turn off after that without saving the changes (this already passed the element when it changed) . Therefore, I have a dirty collection marked as clean.

For a while, I thought I could solve this problem by creating a temporary copy of the collection, mark it clean, and then go ahead and serialize the copy. But copying will be atomic, i.e. e. can I be sure that the collection will not change while I copy it?

Meanwhile, I think I have found better solutions, for example

  • set the lock flag before starting to write to the disk and force the data modification methods to wait until the flag is set
  • so that data modification methods are written to the “change queue” instead of directly to the collection and have a stream that processes the process of writing to disk,

and I think a lock flag might be the best way. But I'm still wondering: is it copying an atomic variable?


Follow up . Perhaps this should be connected with the question, but in fact it is very one and the same. According to the answers below, my “flag blocking” approach might not work either, right? Because the data modification method can check the lock flag when it is set to a “locked” value, and decided that it is not locked. So I need a special design, such as a mutex, if I really want to do it right, right?


Kudos to erickson for his very helpful answer on my follow-up. I really had to ask two questions so that I could accept two answers. Please vote it too.

+6
java multithreading race-condition
source share
7 answers

Not. For example, long variables in Java are not atomic on 32-bit machines.

In addition, there is the problem of "thread caching" - if your variable is not volatile or inside a synchronized block, another thread may not see the change in the value of the variable. This is true for all types of variables, not just.

Read here: http://gee.cs.oswego.edu/dl/cpj/jmm.html , especially the paragraphs “atomicity” and “visibility”.

+13
source share

No, it's not atomic. Look at this question why and what to do with it.

+6
source share

Take a look at java.util.concurrent.atomic - there may be some good things you can use.

+4
source share

You should be concerned about the visibility of changes in other threads when working with the JVM. In general, you must fulfill your assignments in a synchronized block, or the variable must be volatile , or you must use the variable wrapper from the java.util.concurrent.atomic package.

However, in your case, it sounds as if you have only one stream that ever clears the dirty flag - mdash - a stream that is stored in the data. In this case, clear the flag before writing data. If other streams set it during data recording, it will remain set until the next scheduled recording. I would use AtomicBoolean to give you the fluidity of the persistence atom between checking a flag and clearing it, for example:

 private final AtomicBoolean dirty = new AtomicBoolean(); /** * Any method that modifies the data structure should set the dirty flag. */ public void modify() { /* Modify the data first. */ ... /* Set the flag afterward. */ dirty.set(true); } private class Persister extends Thread { public void run() { while (!Thread.interrupted()) { if (dirty.getAndSet(false)) { /* The dirty flag was set; this thread cleared it * and should now persist the data. */ ... } } } } 
+2
source share

A 32-bit installation (at least in .NET) is atomic, but it doesn't suit you. You have to read it to find out if it is blocked, so you can read it, and after reading someone else will read it before you can install it, so two streams get into the protected code. This is what real synchronization objects are (for example, the .NET Monitor class). You can use a lock to check and increment a lock variable.

See also: Is access to a variable in C # an atomic operation?

+1
source share

Depends heavily on the hardware and JVM you use

On some hardware and some JVMs, some copies will be atomic but it is safer to assume that this is not so, even a simple integer with an assignment can translate to four machine instructions on x856 hardware.

Copies of strings and arrays can include a sequence of thousands of instructions and it is possible for two streams to be updated at the same time.

0
source share

As I understand it, not always.

Int32 will, Int64 will not be on a 32-bit system, since it needs 2 x 32 bits. Therefore, it does not fit into a single 32-bit cell.

-2
source share

All Articles