Thread Synchronization: Ensuring Atomic Operations

An atomic operation in computer science refers to a set of operations that can be combined so that they appear to the rest of the system to be a single operation with only two possible outcomes: success or failure (Wikipedia).

In a threaded application certain variables or objects may be shared by multiple threads. If these variables are accessed by two or more threads at the same time it will produce unpredictable results. These operations cannot be termed as atomic.

This article describes how to ensure atomic operations in a multi-threaded environment.

Non Atomic Operation

In most of my previous articles I have attached a sample piece of code to simulate the problem situation. But since non atomic operations are unpredictable, there is no way that I can simulate it purposely through code. So well have to do with all theory this time.

Following two examples describe two cases of non atomic operations occurring when two threads try to simultaneously access a variable.

Example 1

A memory variable is being accessed by two threads. The original value of the variable is ‘A’.

The first thread reads this value and wants to write value ‘B’ to it. But if this thread does not get the next CPU cycle for writing the value, the value of the variable still remains ‘A’.

Instead the second thread gets the subsequent cycle. The second thread reads the original value ‘A’ and not ‘B’ from the thread. Then successfully writes another value ‘C’ to the variable.

Now, when the first thread regains a CPU cycle it will overwrite the value of the variable to ‘B’ without knowing the original value has changed.

So you might say what’s the big deal if the original value is not known. Well suppose that there was an exception in the last step and in the catch block we have some code that reverts back the initial state. What value do you think the first thread will revert back to?

Example 2

Variables are stored in memory in the form of bits. An integer variable requires 32 bits, a short requires 16 bits and a long requires 64 bits where as a string takes up variable amount of memory depending on its length.

Most CPUs today are either 32 bit or 64 bit. A 32 bit CPU can access memory in packets or quantum of 32 bit in each CPU cycle. Similarly a 64 bit processor can access a memory of 64 bits in each CPU cycle.

So a 32 bit processor can access an integer in a single CPU cycle, but will require two CPU cycles for accessing a 64 bit long.

Consider a case of threading on a multi-core CPU where two threads running on different cores access the same long variable. The first thread manipulates the first 32 bits and second thread manipulates the next 32 bits. This will result in an unexpected value for the variable.

The Solution

Ok so finally for the solution. We achieve atomic operations by locking the variable we want to modify.

Show Code

Until the lock is acquired on an object “test”; no other thread will be allowed to access the object. This ensures that only one thread accesses the resource at a time.

The entire operation between the {…} is atomic since the variable test is locked. So any operation performed between the braces will atomic.

But if another object is being accessed in this scope which might be locked by some other process, then this may cause a deadlock, and the “test” object will get locked indefinitely. So you should be very careful before using locks.

Another piece of advice, declare “test” as a global object. If it is declared in local scope, a new instance of “test” will be created each time a thread tries to access it. Since each thread will lock a new instance of thread “test”, the operation will no longer be atomic.

Download Sample
LockingSample.zip

    • kumar
    • April 27th, 2009 11:28pm

    u mean automic operation are synchronize operation?

  1. Hi @kumar,
    What I mean is one of the important steps in synchronizing threads is ensuring that the operations they perform are atomic.

  1. No trackbacks yet.

Spam protection by WP Captcha-Free