15.01.2013 Views

Free-ebooks-library - Bahar Ali Khan

Free-ebooks-library - Bahar Ali Khan

Free-ebooks-library - Bahar Ali Khan

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Exchange and CompareExchange methods, the latter enabling lock-free read-modifywrite<br />

operations, with a little additional coding.<br />

A statement is intrinsically atomic if it executes as a single indivisible instruction on<br />

the underlying processor. Strict atomicity precludes any possibility of preemption.<br />

A simple read or write on a field of 32 bits or less is always atomic. Operations on<br />

64-bit fields are guaranteed to be atomic only in a 64-bit runtime environment, and<br />

statements that combine more than one read/write operation are never atomic:<br />

class Atomicity<br />

{<br />

static int _x, _y;<br />

static long _z;<br />

static void Test()<br />

{<br />

long myLocal;<br />

_x = 3; // Atomic<br />

_z = 3; // Nonatomic on 32-bit environs (_z is 64 bits)<br />

myLocal = _z; // Nonatomic on 32-bit environs (_z is 64 bits)<br />

_y += _x; // Nonatomic (read AND write operation)<br />

_x++; // Nonatomic (read AND write operation)<br />

}<br />

}<br />

Reading and writing 64-bit fields is nonatomic on 32-bit environments because it<br />

requires two separate instructions: one for each 32-bit memory location. So, if thread<br />

X reads a 64-bit value while thread Y is updating it, thread X may end up with a<br />

bitwise combination of the old and new values (a torn read).<br />

The compiler implements unary operators of the kind x++ by reading a variable,<br />

processing it, and then writing it back. Consider the following class:<br />

class ThreadUnsafe<br />

{<br />

static int _x = 1000;<br />

static void Go() { for (int i = 0; i < 100; i++) _x--; }<br />

}<br />

Putting aside the issue of memory barriers, you might expect that if 10 threads concurrently<br />

run Go, _x would end up as 0. However, this is not guaranteed, because a<br />

race condition is possible whereby one thread preempts another in between retrieving<br />

_x’s current value, decrementing it, and writing it back (resulting in an out-of-date<br />

value being written).<br />

Of course, you can address these issues by wrapping the nonatomic operations in a<br />

lock statement. Locking simulates atomicity if consistently applied, but the<br />

Interlocked class provides an easier and faster solution for such simple operations:<br />

class Program<br />

{<br />

static long _sum;<br />

Nonblocking Synchronization | 831<br />

Threading

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!