The following bool property is not thread-safe.
public class NuclearPowerPlant
{
public bool MeltdownIsHappeningRightNow { get; set; }
}
Code language: C# (cs)
Why is this thread un-safe?
Let’s say you have two threads running at the same time. One thread is reading the bool property, while the other thread is changing the value from false to true. It’s possible for the reader thread to get the stale value (false instead of true).
You’ll have to decide if this matters in your system or not. It may be OK for your code to read stale values. If it’s critical that you read the correct values each time, then you’ll need to make the property thread-safe.
In this article, I’ll show two ways to make this property thread-safe: by using a lock and by using the Interlocked class.
Blocking approach – use a lock
Locks only allow one thread into the locked section at a time. When other threads hit the lock, they’ll block until the lock is released. This incurs overhead, but it guarantees thread-safety. There’s always a price to pay for thread-safety.
The following code shows how to use a lock to make the bool property thread-safe.
public class NuclearPowerPlant
{
private object meltdownLock = new object();
private bool _meltdownIsHappening;
public bool MeltdownIsHappeningRightNow
{
get
{
lock (meltdownLock)
{
return _meltdownIsHappening;
}
}
set
{
lock (meltdownLock)
{
_meltdownIsHappening = value;
}
}
}
}
Code language: C# (cs)
Nonblocking approach – use the Interlocked class
Locks are deceivingly complex. They spread complexity all over the code that uses them. The more places that use the locks, the more complex the code gets.
Bad code is complex all over. Good code isolates complexity and shields the rest of the code from it.
The Interlocked class provides a lock-free, non-blocking approach to thread-safety. Not only does it isolate the complexity, but it also provides better performance by eliminating the overhead incurred by locks.
The following code shows how to use the Interlocked class to make the bool property thread-safe.
public class NuclearPowerPlant
{
private long _meltdownIsHappening = 0;
public bool MeltdownIsHappeningRightNow
{
get
{
/* Interlocked.Read() is only available for int64,
* so we have to represent the bool as a long with 0's and 1's
*/
return Interlocked.Read(ref _meltdownIsHappening) == 1;
}
set
{
Interlocked.Exchange(ref _meltdownIsHappening, Convert.ToInt64(value));
}
}
}
Code language: C# (cs)
Comments are closed.