Benefits of locking a variable? [duplicate] - c#

Lets just say you have a simple operation that runs on a background thread. You want to provide a way to cancel this operation so you create a boolean flag that you set to true from the click event handler of a cancel button.
private bool _cancelled;
private void CancelButton_Click(Object sender ClickEventArgs e)
{
_cancelled = true;
}
Now you're setting the cancel flag from the GUI thread, but you're reading it from the background thread. Do you need to lock before accessing the bool?
Would you need to do this (and obviously lock in the button click event handler too):
while(operationNotComplete)
{
// Do complex operation
lock(_lockObject)
{
if(_cancelled)
{
break;
}
}
}
Or is it acceptable to do this (with no lock):
while(!_cancelled & operationNotComplete)
{
// Do complex operation
}
Or what about marking the _cancelled variable as volatile. Is that necessary?
[I know there is the BackgroundWorker class with it's inbuilt CancelAsync() method, but I'm interested in the semantics and use of locking and threaded variable access here, not the specific implementation, the code is just an example.]
There seems to be two theories.
1) Because it is a simple inbuilt type (and access to inbuilt types is atomic in .net) and because we are only writing to it in one place and only reading on the background thread there is no need to lock or mark as volatile.
2) You should mark it as volatile because if you don't the compiler may optimise out the read in the while loop because it thinks nothing it capable of modifying the value.
Which is the correct technique? (And why?)
[Edit: There seem to be two clearly defined and opposing schools of thought on this. I am looking for a definitive answer on this so please if possible post your reasons and cite your sources along with your answer.]

Firstly, threading is tricky ;-p
Yes, despite all the rumours to the contrary, it is required to either use lock or volatile (but not both) when accessing a bool from multiple threads.
For simple types and access such as an exit flag (bool), then volatile is sufficient - this ensures that threads don't cache the value in their registers (meaning: one of the threads never sees updates).
For larger values (where atomicity is an issue), or where you want to synchronize a sequence of operations (a typical example being "if not exists and add" dictionary access), a lock is more versatile. This acts as a memory-barrier, so still gives you the thread safety, but provides other features such as pulse/wait. Note that you shouldn't use a lock on a value-type or a string; nor Type or this; the best option is to have your own locking object as a field (readonly object syncLock = new object();) and lock on this.
For an example of how badly it breaks (i.e. looping forever) if you don't synchronize - see here.
To span multiple programs, an OS primitive like a Mutex or *ResetEvent may also be useful, but this is overkill for a single exe.

_cancelled must be volatile. (if you don't choose to lock)
If one thread changes the value of _cancelled, other threads might not see the updated result.
Also, I think the read/write operations of _cancelled are atomic:
Section 12.6.6 of the CLI spec states:
"A conforming CLI shall guarantee that
read and write access to properly
aligned memory locations no larger
than the native word size is atomic
when all the write accesses to a
location are the same size."

Locking is not required because you have a single writer scenario and a boolean field is a simple structure with no risk of corrupting the state (while it was possible to get a boolean value that is neither false nor true). But you have to mark the field as volatile to prevent the compiler from doing some optimizations. Without the volatile modifier the compiler could cache the value in a register during the execution of your loop on your worker thread and in turn the loop would never recognize the changed value. This MSDN article (How to: Create and Terminate Threads (C# Programming Guide)) addresses this issue.
While there is need for locking, a lock will have the same effect as marking the field volatile.

For thread synchronization, it's recommended that you use one of the EventWaitHandle classes, such as ManualResetEvent. While it's marginally simpler to employ a simple boolean flag as you do here (and yes, you'd want to mark it as volatile), IMO it's better to get into the practice of using the threading tools. For your purposes, you'd do something like this...
private System.Threading.ManualResetEvent threadStop;
void StartThread()
{
// do your setup
// instantiate it unset
threadStop = new System.Threading.ManualResetEvent(false);
// start the thread
}
In your thread..
while(!threadStop.WaitOne(0) && !operationComplete)
{
// work
}
Then in the GUI to cancel...
threadStop.Set();

Look up Interlocked.Exchange(). It does a very fast copy into a local variable which can be used for comparison. It is faster than lock().

Related

thread-safety of primitive concurrent read and write

Simplified illustration below, how does .NET deal with such a situation?
and if it would cause problems, would i have to lock/gate access to each and every field/property that might at times be written to + accessed from different threads?
A field somewhere
public class CrossRoads(){
public int _timeouts;
}
A background thread writer
public void TimeIsUp(CrossRoads crossRoads){
crossRoads._timeouts++;
}
Possibly at the same time, trying to read elsewhere
public void HowManyTimeOuts(CrossRoads crossRoads){
int timeOuts = crossRoads._timeouts;
}
The simple answer is that the above code has the ability to cause problems if accessed simultaneously from multiple threads.
The .Net framework provides two solutions: interlocking and thread synchronization.
For simple data type manipulation (i.e. ints), interlocking using the Interlocked class will work correctly and is the recommended approach.
In fact, interlocked provides specific methods (Increment and Decrement) that make this process easy:
Add an IncrementCount method to your CrossRoads class:
public void IncrementCount() {
Interlocked.Increment(ref _timeouts);
}
Then call this from your background worker:
public void TimeIsUp(CrossRoads crossRoads){
crossRoads.IncrementCount();
}
The reading of the value, unless of a 64-bit value on a 32-bit OS, are atomic. See the Interlocked.Read method documentation for more detail.
For class objects or more complex operations, you will need to use thread synchronization locking (lock in C# or SyncLock in VB.Net).
This is accomplished by creating a static synchronization object at the level the lock is to be applied (for example, inside your class), obtaining a lock on that object, and performing (only) the necessary operations inside that lock:
private static object SynchronizationObject = new Object();
public void PerformSomeCriticalWork()
{
lock (SynchronizationObject)
{
// do some critical work
}
}
The good news is that reads and writes to ints are guaranteed to be atomic, so no torn values. However, it is not guaranteed to do a safe ++, and the read could potentially be cached in registers. There's also the issue of instruction re-ordering.
I would use:
Interlocked.Increment(ref crossroads._timeouts);
For the write, which will ensure no values are lost, and;
int timeouts = Interlocked.CompareExchange(ref crossroads._timeouts, 0, 0);
For the read, since this observes the same rules as the increment. Strictly speaking "volatile" is probably enough for the read, but it is so poorly understood that the Interlocked seems (IMO) safer. Either way, we're avoiding a lock.
Well, I'm not a C# developer, but this is how it typically works at this level:
how does .NET deal with such a situation?
Unlocked. Not likely to be guaranteed to be atomic.
Would i have to lock/gate access to each and every field/property that might at times be written to + accessed from different threads?
Yes. An alternative would be to make a lock for the object available to the clients, then tell the clients they must lock the object while using the instance. This will reduce the number of locks acquisitions, and guarantee a more consistent, predictable, state for your clients.
Forget dotnet. At the machine language level, crossRoads._timeouts++ will be implemented as an INC [memory] instruction. This is known as a Read-Modify-Write instruction. These instructions are atomic with respect to multi-threading on a single processor*, (essentially implemented with time-slicing,) but are not atomic with respect to multi-threading using multiple processors or multiple cores.
So:
If you can guarantee that only TimeIsUp() will ever modify crossRoads._timeouts, and if you can guarantee that only one thread will ever execute TimeIsUp(), then it will be safe to do this. The writing in TimeIsUp() will work fine, and the reading in HowManyTimeOuts() (and any place else) will work fine. But if you also modify crossRoads._timeouts elsewhere, or if you ever spawn one more background thread writer, you will be in trouble.
In either case, my advice would be to play it safe and lock it.
(*) They are atomic with respect to multi-threading on a single processor because context switches between threads happen on a periodic interrupt, and on the x86 architectures these instructions are atomic with respect to interrupts, meaning that if an interrupt occurs while the CPU is executing such an instruction, the interrupt will wait until the instruction completes. This does not hold true with more complex instructions, for example those with the REP prefix.
Although an int may be 'native' size to a CPU (dealing in 32 or 64 bits at a time), if you are reading and writing from different threads to the same variable, you are best off locking this variable and synchronizing access.
There is never a guarantee that reads/writes maybe atomic to an int.
You can also use Interlocked.Increment for your purposes here.

Keeping boolean values in sync between two threads

In one thread (thread2) I have changed a value e.g.
CheckSuccess = false;
Now the main thread (thread1 - GUI / Form) does not pickup the change, how would it be possible to "propogate" the changes around all threads?
I was under the impression that threads should manipulate the data, not work on seperate instances (unless told to do so)
It seems like a Race Condition. To avoid this you should synchronize an access to the shared variables.
If CheckSuccess is a field - try out marking it by volatile keyword.
If CheckSuccess is a property (which will be translated to a method call) you can use lock() statement:
private static readonly object stateLock = new object();
lock (stateLock)
{
// access a shared variable here
CheckSuccess = false;
}
If CheckSuccess is a property of UI control and you want changing it from a worker thread - you should use special techniques to push changes from a worker to the UI thread, it depends on which framework you are using WinForms of WPF.
WinForms - How to update GUI from another thread in C#?
WPF - Update WPF controls at run time
PS:
Also if you have multiple threads reading a value and few threads writing (basically reads more often than writing) you may find useful ReaderWriterLock
I normally use Interlocked methods such as Exchange. This is much simpler than using a locking object and it's guaranteed to be atomic.
The problem is most likely compiler optimizations causing the caching of the boolean value in a CPU register. Declaring it as volatile should solve your problem.

What is a best approach to make a function or set of statements thread safe in C#?

What is a best approach to make a function or set of statements thread safe in C#?
Don't use shared read/write state when possible. Go with immutable types.
Take a look at the C# lock statement. Read Jon Skeet's article on multi threading in .net.
It depends on what you're trying to accomplish.
If you want to make sure that in any given time only one thread would run a specific code use lock or Monitor:
public void Func(...)
{
lock(syncObject)
{
// only one thread can enter this code
}
}
On the other hand you want multiple threads to run the same code but do not want them to cause race conditions by changing the same point in memory don't write to static/shared objects which can be reached by multiple at the same time.
BTW - If you want to create a static object that would be shared only within a single thread use the ThreadStatic attribute (http://msdn.microsoft.com/en-us/library/system.threadstaticattribute(VS.71).aspx).
Use lock statement around shared state variables. Once you ensured thread safety, run code through code profiler to find bottlenecks and optimize those places with more advanced multi-threading constructs.
The best approach will vary depending on your exact problem at hand.
The simplest approach in C# is to "lock" resources shared by multiple threads using a lock statement. This creates a block of code which can only be accessed by one thread at a time: the one which has obtained the "lock" object. For example, this property is thread safe using the lock syntax:
public class MyClass
{
private int _myValue;
public int MyProperty
{
get
{
lock(this)
{
return _myValue;
}
}
set
{
lock(this)
{
_myValue = value;
}
}
}
}
A thread aquires the lock at the start of the block and only releases the lock at the end of the block. If the lock is not available, the thread will wait until the lock is available. Obviously, access to the private variable within the class is not thread-safe, so all threads must access the value through the property to be safe.
This is by far the simplest way for threads to have safe access to shared data, however it only touches the tip of the iceberg of techniques for threading.
Write the function in such a way that:
It does not modify its parameters in any way
It does not access any state outside of its local variables.
Otherwise, race conditions MAY occur. The code must be thoroughly examined for such conditions and appropriate thread synchronization must be implemented (locks, etc...). Writing code that does not require synchronization is the best way to make it thread-safe. Of course, this is often not possible - but should be the first option considered in most situations.
There's a lot to understand when learning what "thread safe" means and all the issues that are introduced (synchronization, etc).
I'd recommend reading through this page in order to get a better feel for what you're asking: Threading in C#. It gives a pretty comprehensive overview of the subject, which sounds like it could be pretty helpful.
And Mehrdad's absolutely right -- go with immutable types if you can help it.

Do I need to lock or mark as volatile when accessing a simple boolean flag in C#?

Lets just say you have a simple operation that runs on a background thread. You want to provide a way to cancel this operation so you create a boolean flag that you set to true from the click event handler of a cancel button.
private bool _cancelled;
private void CancelButton_Click(Object sender ClickEventArgs e)
{
_cancelled = true;
}
Now you're setting the cancel flag from the GUI thread, but you're reading it from the background thread. Do you need to lock before accessing the bool?
Would you need to do this (and obviously lock in the button click event handler too):
while(operationNotComplete)
{
// Do complex operation
lock(_lockObject)
{
if(_cancelled)
{
break;
}
}
}
Or is it acceptable to do this (with no lock):
while(!_cancelled & operationNotComplete)
{
// Do complex operation
}
Or what about marking the _cancelled variable as volatile. Is that necessary?
[I know there is the BackgroundWorker class with it's inbuilt CancelAsync() method, but I'm interested in the semantics and use of locking and threaded variable access here, not the specific implementation, the code is just an example.]
There seems to be two theories.
1) Because it is a simple inbuilt type (and access to inbuilt types is atomic in .net) and because we are only writing to it in one place and only reading on the background thread there is no need to lock or mark as volatile.
2) You should mark it as volatile because if you don't the compiler may optimise out the read in the while loop because it thinks nothing it capable of modifying the value.
Which is the correct technique? (And why?)
[Edit: There seem to be two clearly defined and opposing schools of thought on this. I am looking for a definitive answer on this so please if possible post your reasons and cite your sources along with your answer.]
Firstly, threading is tricky ;-p
Yes, despite all the rumours to the contrary, it is required to either use lock or volatile (but not both) when accessing a bool from multiple threads.
For simple types and access such as an exit flag (bool), then volatile is sufficient - this ensures that threads don't cache the value in their registers (meaning: one of the threads never sees updates).
For larger values (where atomicity is an issue), or where you want to synchronize a sequence of operations (a typical example being "if not exists and add" dictionary access), a lock is more versatile. This acts as a memory-barrier, so still gives you the thread safety, but provides other features such as pulse/wait. Note that you shouldn't use a lock on a value-type or a string; nor Type or this; the best option is to have your own locking object as a field (readonly object syncLock = new object();) and lock on this.
For an example of how badly it breaks (i.e. looping forever) if you don't synchronize - see here.
To span multiple programs, an OS primitive like a Mutex or *ResetEvent may also be useful, but this is overkill for a single exe.
_cancelled must be volatile. (if you don't choose to lock)
If one thread changes the value of _cancelled, other threads might not see the updated result.
Also, I think the read/write operations of _cancelled are atomic:
Section 12.6.6 of the CLI spec states:
"A conforming CLI shall guarantee that
read and write access to properly
aligned memory locations no larger
than the native word size is atomic
when all the write accesses to a
location are the same size."
Locking is not required because you have a single writer scenario and a boolean field is a simple structure with no risk of corrupting the state (while it was possible to get a boolean value that is neither false nor true). But you have to mark the field as volatile to prevent the compiler from doing some optimizations. Without the volatile modifier the compiler could cache the value in a register during the execution of your loop on your worker thread and in turn the loop would never recognize the changed value. This MSDN article (How to: Create and Terminate Threads (C# Programming Guide)) addresses this issue.
While there is need for locking, a lock will have the same effect as marking the field volatile.
For thread synchronization, it's recommended that you use one of the EventWaitHandle classes, such as ManualResetEvent. While it's marginally simpler to employ a simple boolean flag as you do here (and yes, you'd want to mark it as volatile), IMO it's better to get into the practice of using the threading tools. For your purposes, you'd do something like this...
private System.Threading.ManualResetEvent threadStop;
void StartThread()
{
// do your setup
// instantiate it unset
threadStop = new System.Threading.ManualResetEvent(false);
// start the thread
}
In your thread..
while(!threadStop.WaitOne(0) && !operationComplete)
{
// work
}
Then in the GUI to cancel...
threadStop.Set();
Look up Interlocked.Exchange(). It does a very fast copy into a local variable which can be used for comparison. It is faster than lock().

Does an EventWaitHandle have any implicit MemoryBarrier?

New to this website, so let me know if I'm not posting in an accepted manner.
I've frequently coded something along the lines of the sample below(with stuff like Dispose ommited for clarity. ). My question is, are the volatiles needed as shown? Or does the ManualResetEvent.Set have an implicit memory barrier as I've read Thread.Start does? Or would an explicit MemoryBarrier call be better than the volatiles? Or is it completely wrong? Also, the fact that the "implicit memory barrier behavior" in some operations is not documented as far as I've seen is quite frutrating, is there a list of these operations somewhere?
Thanks,
Tom
:
class OneUseBackgroundOp
{
// background args
private string _x;
private object _y;
private long _z;
// background results
private volatile DateTime _a
private volatile double _b;
private volatile object _c;
// thread control
private Thread _task;
private ManualResetEvent _completedSignal;
private volatile bool _completed;
public bool DoSomething(string x, object y, long z, int initialWaitMs)
{
bool doneWithinWait;
_x = x;
_y = y;
_z = z;
_completedSignal = new ManualResetEvent(false);
_task = new Thread(new ThreadStart(Task));
_task.IsBackground = true;
_task.Start()
doneWithinWait = _completedSignal.WaitOne(initialWaitMs);
return doneWithinWait;
}
public bool Completed
{
get
{
return _completed;
}
}
/* public getters for the result fields go here, with an exception
thrown if _completed is not true; */
private void Task()
{
// args x, y, and z are written once, before the Thread.Start
// implicit memory barrier so they may be accessed freely.
// possibly long-running work goes here
// with the work completed, assign the result fields _a, _b, _c here
_completed = true;
_completedSignal.Set();
}
}
Note that this is off the cuff, without studying your code closely. I don't think Set performs a memory barrier, but I don't see how that's relevant in your code? Seems like more important would be if Wait performs one, which it does. So unless I missed something in the 10 seconds I devoted to looking at your code, I don't believe you need the volatiles.
Edit: Comments are too restrictive. I'm now referring to Matt's edit.
Matt did a good job with his evaluation, but he's missing a detail. First, let's provide some definitions of things thrown around, but not clarified here.
A volatile read reads a value and then invalidates the CPU cache. A volatile write flushes the cache, and then writes the value. A memory barrier flushes the cache and then invalidates it.
The .NET memory model ensures that all writes are volatile. Reads, by default, are not, unless an explicit VolatileRead is made, or the volatile keyword is specified on the field. Further, interlocked methods force cache coherency, and all of the synchronization concepts (Monitor, ReaderWriterLock, Mutex, Semaphore, AutoResetEvent, ManualResetEvent, etc.) call interlocked methods internally, and thus ensure cache coherency.
Again, all of this is from Jeffrey Richter's book, "CLR via C#".
I said, initially, that I didn't think Set performed a memory barrier. However, upon further reflection about what Mr. Richter said, Set would be performing an interlocked operation, and would thus also ensure cache coherency.
I stand by my original assertion that volatile is not needed here.
Edit 2: It looks as if you're building a "future". I'd suggest you look into PFX, rather than rolling your own.
The volatile keyword should not confused as to making _a, _b, and _c thread-safe. See here for a better explanation. Further, the ManualResetEvent does not have any bearing on the thread-safety of _a, _b, and _c. You have to manage that separately.
EDIT: With this edit, I am attempting to distill all of the information that has been put in various answers and comments regarding this question.
The basic question is whether or not the result variables (_a, _b, and _c) will be 'visible' at the time the flag variable (_completed) returns true.
For a moment, let's assume that none of the variables are marked volatile. In this case, it would be possible for the result variables to be set after the flag variable is set in Task(), like this:
private void Task()
{
// possibly long-running work goes here
_completed = true;
_a = result1;
_b = result2;
_c = result3;
_completedSignal.Set();
}
This is clearly not what we want, so how do we deal with this?
If these variables are marked volatile, then this reordering will be prevented. But that is what prompted the original question - are the volatiles required or does the ManualResetEvent provide an implicit memory barrier such that reordering does not occur, in which case the volatile keyword is not really necessary?
If I understand correctly, wekempf's position is that the WaitOne() function provides an implicit memory barrier which fixes the problem. BUT that doesn't seem sufficient to me. The main and background threads could be executing on two separate processors. So, if Set() does not also provide an implicit memory barrier, then the Task() function could end up being executed like this on one of the processors (even with the volatile variables):
private void Task()
{
// possibly long-running work goes here
_completedSignal.Set();
_a = result1;
_b = result2;
_c = result3;
_completed = true;
}
I have searched high and low for information regarding memory barriers and the EventWaitHandles, and I have come up with nothing. The only reference I have seen is the one wekempf has made to Jeffrey Richter's book. The problem I have with this is that the EventWaitHandle is meant to synchronize threads, not access to data. I have never seen any example where EventWaitHandle (e.g., ManualResetEvent) is used to synchronize access to data. As such, I'm hard-pressed to believe that EventWaitHandle does anything with regard to memory barriers. Otherwise, I would expect to find some reference to this on the internet.
EDIT #2: This is a response to wekempf's response to my response... ;)
I managed to read the section from Jeffrey Richter's book at amazon.com. From page 628 (wekempf quotes this too):
Finally, i should point out that whenever a thread calls an interlocked method, the CPU forces cache coherency. So if you are manipulating variables via interlocked methods, you do not have to worry about all of this memory model stuff. Furthermore, all thread synchronization locks (Monitor, ReaderWriterLock, Mutex, Semaphone, AutoResetEvent, ManualResetEvent, etc.) call interlocked methods internally.
So it would seem that, as wekempf pointed out, that the result variables do not require the volatile keyword in the example as shown since the ManualResetEvent ensures cache coherency.
Before closing this edit, there are two additional points I'd like to make.
First, my initial assumption was that the background thread would potentially run multiple times. I obviously overlooked the name of the class (OneUseBackgroundOp)! Given that it is only run once, it is not clear to me why the DoSomething() function calls WaitOne() in the manner that it does. What is the point of waiting initialWaitMs milliseconds if the background thread may or may not be done at the time DoSomething() returns? Why not just kickoff the background thread and use a lock to synchronize access to the results variables OR simply execute the contents of the Task() function as part of the thread that calls DoSomething()? Is there a reason not to do this?
Second, it seems to me that not using some kind of locking mechanism on the results variables is still a bad approach. True, it is not needed in the code as shown. But at some point down the road, another thread may come along and try to access the data. It would be better in my mind to prepare for this possibility now rather than try to track down mysterious behavior anomalies later.
Thanks to everyone for bearing with me on this. I've certainly learned a lot by participating in this discussion.
Wait functions have an implicit memory barrier. See http://msdn.microsoft.com/en-us/library/ms686355(v=vs.85).aspx
First, I'm not sure if I should "Answer my own question" or use a comment for this, but here goes:
My understanding is that volatile prevents code/memory optimizations from moving the accesses to my result variables (and the completed boolean) such that the the thread that reads the result will see upt-to-date data.
You wouldn't want the _completed boolean made visible to all threads after the Set() due to compiler or emmpry optimaztions/reordering. Likewise, you wouldn't want the writes to the results _a, _b, _c being seen after the Set().
EDIT: Further explaination/clarification on the question, in regards to items mentioned by Matt Davis:
Finally, i should point out that
whenever a thread calls an interlocked
method, the CPU forces cache
coherency. So if you are manipulating
variables via interlocked methods, you
do not have to worry about all of this
memory model stuff. Furthermore, all
thread synchronization locks (Monitor,
ReaderWriterLock, Mutex, Semaphone,
AutoResetEvent, ManualResetEvent,
etc.) call interlocked methods
internally.
So it would seem that, as wekempf
pointed out, that the result variables
do not require the volatile keyword in
the example as shown since the
ManualResetEvent ensures cache
coherency.
So you are both in agreement that such an operation takes care of caching between processors or in registers etc.
But does it prevent reording to guarantee such that BOTH the results are assigned before the completed flag, and that the completed flag is assigned true before the ManualResetEvent is Set?
First, my initial assumption was that
the background thread would
potentially run multiple times. I
obviously overlooked the name of the
class (OneUseBackgroundOp)! Given that
it is only run once, it is not clear
to me why the DoSomething() function
calls WaitOne() in the manner that it
does. What is the point of waiting
initialWaitMs milliseconds if the
background thread may or may not be
done at the time DoSomething()
returns? Why not just kickoff the
background thread and use a lock to
synchronize access to the results
variables OR simply execute the
contents of the Task() function as
part of the thread that calls
DoSomething()? Is there a reason not
to do this?
The concept of the sample is to execute a possibly long-runnig task. If the task can be completed within an exceptable amount of time, then the calling thread will get access to the result and continue with normal processing. But sometime a task can take quite a long time and the claiing thread cannot be blocked for that period and can take reasonable steps to deal with that. That can include checking back later on the operation using the Completed property.
A concrete example: A DNS resolve is often very quick (subsecond) and worth waiting for even from a GUI, but sometimes it can take many many seconds. So by using a utility class like the sample, one could gets a result easily from the point-of-view of the caller 95% of the time and not lock up the GUI the other 5%. One could use a Background worker, but that can be overkill for an operation that the vast majority of the time doesn't need all that plumbing.
Second, it seems to me that not using
some kind of locking mechanism on the
results variables is still a bad
approach. True, it is not needed in
the code as shown.
The result (and completed flag) data is meant to be write-once, read-many. If I added a lock to assign the results and flag, I'd also have to lock in my result getters, and I never liked seeing getters lock just to return a data point. From my reading, such fine-grained locking is not appropriate. If an operation has 5 or 6 results, the caller has to take and release the lock 5 or 6 times needlessly.
But at some point
down the road, another thread may come
along and try to access the data. It
would be better in my mind to prepare
for this possibility now rather than
try to track down mysterious behavior
anomalies later.
Because I have a volatile completed flag that is guarenteed to be set before the volatile results are, and the only access to the results is through the getters, and as mentioned in the smaple, an exception is thrown if the getter is called and the operation is not yet complete, I'd expect that the Completed and result getters CAN be invoked by a thread other than the one that called DoSomething(). That's my hope anyway. I believe this to be true with the volatiles anyway.
Based on what you've shown, I would say that, no, the volatiles are not required in that code.
The ManualResetEvent itself doesn't have an implicit memory barrier. However, the fact that the main thread is waiting for the signal means that it can't modify any variables. At least, it can't modify any variables while it's waiting. So I guess you could say that waiting on a synchronization object is an implicit memory barrier.
Note, however, that other threads, if they exist and have access to those variables, could modify them.
From your question, it seems that you're missing the point of what volatile does. All volatile does is tell the compiler that the variable might be modified by other threads asynchronously, so it shouldn't optimize code that accesses the variable. volatile does not in any way synchronize access to the variable.

Categories

Resources