Question

The scenario

I have a class with a bool Enabled property, that is used by a loop on another thread to see whether it should stop or not. The idea is that a different thread can set that property to false and stop the other thread running cleanly.

The question

Should I bother to serialise access to that Enabled property using something like lock (lockObject) { ... }, or is it safe without?

Was it helpful?

Solution

Primitive type reads are atomic provided that they fit within a CPU read. Thus a 32 bit primitive type read is atomic on a 32 bit CPU, whereas a 64 bit type read is not. However, unless it is also volatile your other thread may not see changes due to caching.

OTHER TIPS

I think you only need to mark the boolean variable as volatile. This will ensure that the thread that you wish to stop running always sees the most updated value of this boolean.

If one thread read the value and one other thread write the value, in this case it is safe but pay attention to declare the Enabled property with the volatile keyword to be sure that the value will be synchronized to all processors if you run with a dualcore pc.

As others already stated correctly, volatile can be used (or a lock on the variable) to access a variable's value in a thread safe manner.

Without making the variable volatile the compiler might apply optimization techniques that reorder instructions which might lead to unexpected and unpredictable results.

The relevant part of the C# language specification (10.4.3 Volatile fields) further states:

For volatile fields, such reordering optimizations are restricted:

  • A read of a volatile field is called a volatile read. A volatile read has "acquire semantics"; that is, it is guaranteed to occur prior to any references to memory that occur after it in the instruction sequence.
  • A write of a volatile field is called a volatile write. A volatile write has "release semantics"; that is, it is guaranteed to happen after any memory references prior to the write instruction in the instruction sequence.

These restrictions ensure that all threads will observe volatile writes performed by any other thread in the order in which they were performed. A conforming implementation is not required to provide a single total ordering of volatile writes as seen from all threads of execution. The type of a volatile field must be one of the following:

  • A reference-type.
  • The type byte, sbyte, short, ushort, int, uint, char, float, or bool.
  • An enum-type having an enum base type of byte, sbyte, short, ushort, int, or uint.

If you didn't mark it as volatile it will work on single CPU computers (because of 32 bit atomicity), but not PC's with multiple CPU's as it would hold the value in its on die cache and not retrieve the the very latest value, Hence you need to mark with Volatile. Its true you don't need to lock items if its 32 bits in size as its just a registry sized change and thus atomic.

There is an article on it here: www.yoda.arachsys.com/csharp/threads/volatility.shtml

There is also something called Synchronization Domains.

The synchronization domain provides automatic synchronization of thread access to objects declaratively. This class was introduced as a part of the infrastructure supporting .NET remoting. Developers wishing to indicate that a class is to have access to its objects synchronized must have the class inherit from ContextBoundObject and mark it with the SynchronizationAttribute like so:

[Synchronization]
public class MyController : ContextBoundObject 
{
  /// All access to objects of this type will be intercepted
  /// and a check will be performed that no other threads
  /// are currently in this object's synchronization domain.
}

Further information on Syncronisation domains can be found here: msdn.microsoft.com/en-us/magazine/dd569749.aspx

If you don't use volatile or lock the boolean it will work x86. It may not work on Intel's Itanium CPUs (IA64) though. Here's a good codeproject kb article that explains it all.

You can use Interlocked.Exchange in this case, if you are concerned about an ugly lock.

There is an MSDN example that describes exactly what you are tying to do: How to: Create and Terminate Threads (C# Programming Guide). It suggests that you need to declare your Enabled property as volatile and don't need to lock it.

You could as people already written mark the variable with volatile or lock it.

However, what you're trying to accomplish (allowing threads to communicate with each other by signaling) is already built into the .NET framework.

Take a look at ManualResetEvent at MSDN.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top