views:

111

answers:

3

I commonly write code that is along these lines:

public class MyClass
{
 static bool m_stop = false;

 public static void Main()
 {
  var th = new Thread(DoStuff);

  th.Start();

  Console.ReadLine();

  m_stop = true;

  th.Join();
 }

 private static void DoStuff()
 {
  while( !m_stop )
  {
   // do things here
  }
 }
}

... and I always synchronize access to the variable m_stop, just out of habit. I'm wondering whether it's actually necessary to do that (assuming running an extra loop or two in DoStuff() won't hurt anything). What is the worst that could happen if the code executed exactly like this? I've toyed with the thought of using the volatile keyword for m_stop, but I'm not sure that even that is necessary. Anyone know for sure?

+3  A: 

Without being volatile and without any synchronization, the code that you've shown isn't thread-safe. One thread could change the value of the variable and the other thread might never see it, looping forever. If you synchronize all access to it with a common lock, it is thread-safe.

Now volatility is a tricky topic - I thought I understood it until recently, but it doesn't mean quite what I thought it did. However, I'm pretty sure that just making the variable volatile will do what you need it to.

For anything more complicated, I'd usually use full synchronization: take out a lock every time you access the shared data.

Jon Skeet
The example doesn't show it but the OP does state that they synchronize access to `m_stop`.
Andrew Hare
Ah, that's the key. Will edit.
Jon Skeet
To better understand volatile and the confusion around it please read this (http://www.bluebytesoftware.com/blog/PermaLink,guid,dd3aff8a-7f8d-4de6-a2e7-d199662b68f4.aspx) post by Joe Duffy. Truelly a great read.
Mahin
oops... Jon I am late for that link... did not noticed that link.
Mahin
@Andrew: Actually, having read the question a third time, my original answer was still useful: the OP was asking whether the code *in the question* was thread safe, not the code including the synchronization.
Jon Skeet
@Jon - I agree, I think your answer is useful as well - I was just being picky :)
Andrew Hare
+1 To you by the way - I thought I had already upvoted you but I hadn't.
Andrew Hare
Thanks, Jon, that was exactly the answer I was looking for. Usually I do full synchronization in situations like these, and it looks like it was the safe option.
Mark
+1  A: 

While there is nothing technically wrong with this approach you can get into trouble when your application needs to scale. Also you don't need to make m_stop volatile if you are synchronizing access to it.

Andrew Hare
Your comment directly contradicts Jon's. I don't know who's right, but it seems like an important point. If access to m_stop isn't synchronized, with the value always be propagated to the other thread?
Mark
A: 

you must place a memory barrier when you update *m_stop*. so you will have to mark it as volatile (or place memory barriers/volatile reads-writes yourself)