...

/

Using synchronized to Avoid Race Conditions

Using synchronized to Avoid Race Conditions

Learn how synchronized can be used to avoid race conditions.

We'll cover the following...

Use of synchronized

The incorrect program behavior in the previous lesson is due to more than one thread accessing the same mutable data (and at least one of them modifying it). One way of avoiding these race conditions is to mark the common code with the synchronized keyword. The program will work correctly with the following change:

Press + to interact
import std.stdio;
import std.concurrency;
import core.thread;
void swapper(shared(int) * a, shared(int) * b) {
foreach (i; 0 .. 10_000) {
synchronized {
int temp = *b;
*b = *a;
*a = temp;
}
}
}
void main() {
shared(int) i = 1;
shared(int) j = 2;
writefln("before: %s and %s", i, j);
foreach (id; 0 .. 10) {
spawn(&swapper, &i, &j);
}
// Wait for all threads to finish their tasks
thread_joinAll();
writefln("after : %s and %s", i, j);
}

The output:

before: 1 and 2
after : 1 and 2      ← correct result

The effect of synchronized is to create a lock behind the scenes and allow only one thread to hold that lock at a given time. Only the thread that holds the lock can be executed, and the others wait until the lock becomes available again when the executing thread completes its synchronized block. Since one thread executes the synchronized code at a time, each thread would now swap ...