C# alternative to lock if volatile isn't a good idea - c#

I'm sorry I know this topic has been done to death (I've read I've read this and this and a few more) but there is one issue I have which I am not sure how to do 'correctly'.
Currently my code for a multithreaded Sudoku strategy is the following:
public class MultithreadedStrategy : ISudokuSolverStrategy
{
private Sudoku Sudoku;
private List<Thread> ThreadList = new List<Thread>();
private Object solvedLocker = new Object();
private bool _solved;
public bool Solved // This is slow!
{
get
{
lock (solvedLocker)
{
return _solved;
}
}
set
{
lock (solvedLocker)
{
_solved = value;
}
}
}
private int threads;
private ConcurrentQueue<Node> queue = new ConcurrentQueue<Node>();
public MultithreadedStrategy(int t)
{
threads = t;
Solved = false;
}
public Sudoku Solve(Sudoku sudoku)
{
// It seems concevable to me that there may not be
// a starting point where there is only one option.
// Therefore we may need to search multiple trees.
Console.WriteLine("WARNING: This may require a large amount of memory.");
Sudoku = sudoku;
//Throw nodes on queue
int firstPos = Sudoku.FindZero();
foreach (int i in Sudoku.AvailableNumbers(firstPos))
{
Sudoku.Values[firstPos] = i;
queue.Enqueue(new Node(firstPos, i, false, Sudoku));
}
//Setup threads
for (int i = 0; i < threads; i++)
{
ThreadList.Add(new Thread(new ThreadStart(ProcessQueue)));
ThreadList[i].Name = String.Format("Thread {0}", i + 1);
}
//Set them running
foreach (Thread t in ThreadList)
t.Start();
//Wait until solution found (conditional timeout?)
foreach (Thread t in ThreadList)
t.Join();
//Return Sudoku
return Sudoku;
}
public void ProcessQueue()
{
Console.WriteLine("{0} running...",Thread.CurrentThread.Name);
Node currentNode;
while (!Solved) // ACCESSING Solved IS SLOW FIX ME!
{
if (queue.TryDequeue(out currentNode))
{
currentNode.GenerateChildrenAndRecordSudoku();
foreach (Node child in currentNode.Children)
{
queue.Enqueue(child);
}
// Only 1 thread will have the solution (no?)
// so no need to be careful about locking
if (currentNode.CurrentSudoku.Complete())
{
Sudoku = currentNode.CurrentSudoku;
Solved = true;
}
}
}
}
}
(Yes I have done DFS with and without recursion and using a BFS which is what the above strategy modifies)
I was wondering whether I am allowed to change my private bool _solved; to a private volatile solved; and get rid of the accessors. I think this might be a bad thing because my ProcessQueue() method changes the state of _solved Am I correct? I know booleans are atomic but I don't want compiler optimisations to mess up the order of my read/write statements (esp. since the write only happens once).
Basically the lock statement adds tens of seconds to the run time of this strategy. Without the lock it runs an awful lot faster (although is relatively slow compared to a DFS because of the memory allocation within currentNode.GenerateChildrenAndRecordSudoku()

Before getting into alternatives: it is probably safe to go with a low-lock solution here by making access to the boolean volatile. This situation is ideal, as it is unlikely that you have complex observation-ordering requirements. ("volatile" does not guarantee that multiple volatile operations are observed to have consistent ordering from multiple threads, only that reads and writes have acquire and release semantics.)
However, low-lock solutions make me very nervous and I would not use one unless I was sure I had need to.
The first thing I would do is find out why there is so much contention on the lock. An uncontended lock should take 20-80 nanoseconds; you should only get a significant performance decrease if the lock is contended. Why is the lock so heavily contended? Fix that problem and your performance problems will go away.
The second thing I might do if contention cannot be reduced is to use a reader-writer lock. If I understand your scenario correctly, you will have many readers and only one writer, which is ideal for a reader-writer lock.
Leaving the question of volatility aside: as others have pointed out, there are basic mistakes in your threading logic like spinning on a boolean. This stuff is hard to get right. You might consider using the Task Parallel Library here as a higher-level abstraction than rolling your own threading logic. The TPL is ideally suited for problems where significant work must be done on multiple threads. (Note that the TPL does not magically make not-thread-safe code thread-safe. But it does provide a higher level of abstraction, so that you are dealing with Tasks rather than Threads. Let the TPL schedule the threads for you.)
Finally: the idea that a sudoku solver should take tens of seconds indicates to me that the solver is, frankly, not very good. The sudoku problem is, in its theoretically worst possible case, a hard problem to solve quickly no matter how many threads you throw at it. But for "newspaper" quality sudokus you should be able to write a solver that runs in a fraction of a second. There's no need to farm the work out to multiple threads if you can do the whole thing in a few hundred milliseconds.
If you're interested, I have a C# program that quickly finds solutions to sudoku problems here:
http://blogs.msdn.com/b/ericlippert/archive/tags/graph+colouring/

So the first thing, fix you're while loop to just join the threads...
//Set them running
foreach (Thread t in ThreadList)
t.Start();
//Wait until solution found (conditional timeout?)
foreach (Thread t in ThreadList)
t.Join(/* timeout optional here */);
Then there is issue with when to shutdown the threads. My advise is to introduce a wait handle on the class and then in the worker threads just loop on that...
ManualResetEvent mreStop = new ManualResetEvent(false);
//...
while(!mreStop.WaitOne(0))
{
//...
Now just modify the Solved property to signal all threads that they should quit...
public bool Solved
{
get
{
return _solved;
}
}
// As Eric suggests, this should be a private method, not a property set.
private void SetCompleted()
{
_solved = value;
mreStop.Set();
}
The benefit to this approach is that if a thread fails to quit within a timeout period you can signal the mreStop to stop the workers without setting _solved to true.

volatile IS used to prevent optimizations such as caching and reordering of reads/writes for a single variable. Using it in this case is exactly what it's designed for. I don't see what your concern is.
lock is a slow yet working alternative because it introduces a memory fence implicitly, but in your case you are using a lock just for the memory fence side-effect, which is not really a nice idea.

Related

C# shared variable access from different threads

I am using a static variables to get access between threads, but is taking so long to get their values.
Context: I have a static class Results.cs, where I store the result variables of two running Process.cs instances.
public static int ResultsStation0 { get; set; }
public static int ResultsStation1 { get; set; }
Then, a function of the two process instances is called at the same time, with initial value of ResultsStation0/1 = -1.
Because the result will be provided not at the same time, the function is checking that both results are available. The fast instance will set the result and await for the result of the slower instance.
void StationResult(){
Stopwatch sw = new Stopwatch();
sw.Restart();
switch (stationIndex) //Set the result of the station thread
{
case 0: Results.ResultsStation0 = 1; break;
case 1: Results.ResultsStation1 = 1; break;
}
//Waits to get the results of both threads
while (true)
{
if (Results.ResultsStation0 != -1 && Results.ResultsStation1 != -1)
{
break;
}
}
Trace_Info("GOT RESULTS " + stationIndex + "Time: " + sw.ElapsedMilliseconds.ToString() + "ms");
if (Results.ResultsStation0 == 1 && Results.ResultsStation1 == 1)
{
//set OK if both results are OK
Device.profinet.WritePorts(new Enum[] { NOK, OK },
new int[] { 0, 1 });
}
}
It works, but the problem is that the value of sw of the thread that awaits, should be 1ms more or less. I am getting 1ms sometimes, but most of the times I have values up to 80ms.
My question is: why it takes that much if they are sharing the same memory (I guess)?
Is this the right way to access to a variable between threads?
Don't use this method. Global mutable state is bad enough. Mixing in multiple threads sounds like a recipe for unmaintainable code. Since there is no synchronization at all in sight there is no real guarantee that your program may ever finish. On a single CPU system your loop will prevent any real work from actually being done until the scheduler picks one of the worker threads to run, an even on multi core system you will waste a ton of CPU cycles.
If you really want global variables, these should be something that can signal the completion of the operation, i.e. a Task, or ManualResetEvent. That way you can get rid of your horrible spin-wait, and actually wait for each task to complete.
But I would highly recommend to get rid of the global variables and just use standard task based programming:
var result1 = Task.Run(MyMethod1);
var result2 = Task.Run(MyMethod2);
await Task.WhenAll(new []{result1, result2});
Such code is much easier to reason about and understand.
Multi threaded programming is difficult. There are a bunch of new ways your program can break, and the compiler will not help you. You are lucky if you even get an exception, in many cases you will just get an incorrect result. If you are unlucky you will only get incorrect results in production, not in development or testing. So you should read a fair amount about the topic so that you are at least familiar with the common dangers and the ways to mitigate them.
You are using flags as signaling for this you have a class called AutoResetEvent.
There's a difference between safe access and synchronization.
For safe access (atomic) purpose you can use the class Interlocked
For synchronization you use mutex based solutions - either spinlocks, barriers, etc...
What it looks like is you need a synchronization mechanism because you relay on an atomic behavior to signal a process that it is done.
Further more,
For C# there's the async way to do things and that is to call await.
It is Task based so in case you can redesign your flow to use Tasks instead of Threads it will suit you more.
Just to be clear - atomicity means you perform the call in one go.
So for example this is not atomic
int a = 0;
int b = a; //not atomic - read 'a' and then assign to 'b'.
I won't teach you everything to know about threading in C# in one post answer - so my advice is to read the MSDN articles about threading and tasks.

Is it possible to create a deadlock in C# if nothing but the lock keyword is used around primitive data access?

I've written a lot of multi-threaded C# code, and I've never had a deadlock in any code I've released.
I use the following rules of thumb:
I tend to use nothing but the lock keyword (I also use other techniques such as reader/writer locks, but sparingly, and only if required for speed).
I use Interlocked.Increment if I am dealing with a long.
I tend to use the smallest granular unit of locking: I only tend to lock around primitive data structures such as long, dictionary or list.
I'm wondering if it's even possible to generate a deadlock if these rules are thumb are consistently followed, and if so, what the code would look like?
Update
I also use these rules of thumb:
Avoid adding a lock around anything that could pause indefinitely, especially I/O operations. If you absolutely have to do so, ensure that absolutely everything within the lock will time out after a set TimeSpan.
The objects I use for locking are always dedicated objects, e.g. object _lockDict = new object(); then lock(_lockDict) { // Access dictionary here }.
Update
Great answer from Jon Skeet. It also confirms why I never get deadlocks as I tend to instinctively avoid nested locks, and even if I do use them, I've always instinctively kept the entry order consistent.
And in response to my comment on tending to use nothing but the lock keyword, i.e. using Dictionary + lock instead of ConcurrentDictionary, Jon Skeet made this comment:
#Contango: That's exactly the approach I'd take too.
I'd go for simple code with locking over "clever" lock-free code every time, until there's evidence that it's causing an issue.
Yes, it's easy to deadlock, without actually accessing any data:
private readonly object lock1 = new object();
private readonly object lock2 = new object();
public void Method1()
{
lock(lock1)
{
Thread.Sleep(1000);
lock(lock2)
{
}
}
}
public void Method2()
{
lock(lock2)
{
Thread.Sleep(1000);
lock(lock1)
{
}
}
}
Call both Method1 and Method2 at roughly the same time, and boom - deadlock. Each thread will be waiting for the "inner" lock, which the other thread has acquired as its "outer" lock.
If you make sure you always acquire locks in the same order (e.g. "never acquire lock2 unless you already own lock1) and release the locks in the reverse order (which is implicit if you're acquiring/releasing with lock) then you won't get that sort of deadlock.
You can still get a deadlock with async code, with just a single thread involved - but that involves Task as well:
public async Task FooAsync()
{
BarAsync().Wait(); // Don't do this!
}
public async Task BarAsync()
{
await Task.Delay(1000);
}
If you run that code from a WinForms thread, you'll deadlock in a single thread - FooAsync will be blocking on the task returned by BarAsync, and the continuation for BarAsync won't be able to run because it's waiting to get back onto the UI thread. Basically, you shouldn't issue blocking calls from the UI thread...
As long as you ever only lock on one thing it's impossible, if one thread tries to lock on multiple locks, then yes. The dining philosophers problem nicely illustrates a simple deadlock caused with simple data.
As the other answers have already shown;
void Thread1Method()
{
lock (lock1)
{
// Do smth
lock (lock2)
{ }
}
}
void Thread2Method()
{
lock (lock2)
{
// Do smth
lock (lock2)
{ }
}
}
Addendum to what Skeet wrote:
The problem normally isn't with "only" two locks... (clearly there could be even with only two locks, but we want to play in Hard mode :-) )...
Let's say that in your program there are 10 lockable resources... Let's call them a1...a10. You must be sure that you'll always lock those in the same order, even for subsets of them... If a method needs a3, a5 and a7, and another methods needs a4, a5, a7, you must be sure that both will try locking them in the "right" order. For simplicity sake in this case the order is clear: a1->a10.
Normally lock objects aren't numbered, and/or they aren't taken in a single method... For example:
void MethodA()
{
lock (Lock1)
{
CommonMethod();
}
}
void MethodB()
{
lock (Lock3)
{
CommonMethod();
}
}
void CommonMethod()
{
lock (Lock2)
{
}
}
void MethodC()
{
lock (Lock1)
{
lock (Lock2)
{
lock (Lock3)
{
}
}
}
}
Here, even with the Lock* numbered, it isn't immediately clear that the locks could be taken in the wrong order (MethodB+CommonMethod take Lock3+Lock2, while MethodC takes Lock1+Lock2+Lock3)... It isn't immediately clear and we are playing with three very big advantages: we are speaking of deadlock, so we are looking for them, the locks are numbered and the whole code is around 30 lines.

Under what conditions can a thread enter a lock (Monitor) region more than once concurrently?

(question revised): So far, the answers all include a single thread re-entering the lock region linearly, through things like recursion, where you can trace the steps of a single thread entering the lock twice. But is it possible somehow, for a single thread (perhaps from the ThreadPool, perhaps as a result of timer events or async events or a thread going to sleep and being awaken/reused in some other chunk of code separately) to somehow be spawned in two different places independently of each other, and hence, run into the lock re-entrance problem when the developer didn't expect it by simply reading their own code?
In the ThreadPool Class Remarks (click here) the Remarks seem to suggest that sleeping threads should be reused when they're not in use, or otherwise wasted by sleeping.
But on the Monitor.Enter reference page (click here) they say "It is legal for the same thread to invoke Enter more than once without it blocking." So I figure there must be something I'm supposed to be careful to avoid. What is it? How is it even possible for a single thread to enter the same lock region twice?
Suppose you have some lock region that takes an unfortunately long time. This might be realistic, for example, if you access some memory that has been paged out (or whatever.) The thread in the locked region might go to sleep or something. Does the same thread become eligible to run more code, which might accidentally step into the same lock region? The following does NOT, in my testing, get multiple instances of the same thread to run into the same lock region.
So how does one produce the problem? What exactly do you need to be careful to avoid?
class myClass
{
private object myLockObject;
public myClass()
{
this.myLockObject = new object();
int[] myIntArray = new int[100]; // Just create a bunch of things so I may easily launch a bunch of Parallel things
Array.Clear(myIntArray, 0, myIntArray.Length); // Just create a bunch of things so I may easily launch a bunch of Parallel things
Parallel.ForEach<int>(myIntArray, i => MyParallelMethod());
}
private void MyParallelMethod()
{
lock (this.myLockObject)
{
Console.Error.WriteLine("ThreadId " + Thread.CurrentThread.ManagedThreadId.ToString() + " starting...");
Thread.Sleep(100);
Console.Error.WriteLine("ThreadId " + Thread.CurrentThread.ManagedThreadId.ToString() + " finished.");
}
}
}
Suppose you have a queue that contains actions:
public static Queue<Action> q = whatever;
Suppose Queue<T> has a method Dequeue that returns a bool indicating whether the queue could be successfully dequeued.
And suppose you have a loop:
static void Main()
{
q.Add(M);
q.Add(M);
Action action;
while(q.Dequeue(out action))
action();
}
static object lockObject = new object();
static void M()
{
Action action;
lock(lockObject)
{
if (q.Dequeue(out action))
action();
}
}
Clearly the main thread enters the lock in M twice; this code is re-entrant. That is, it enters itself, through an indirect recursion.
Does this code look implausible to you? It should not. This is how Windows works. Every window has a message queue, and when a message queue is "pumped", methods are called corresponding to those messages. When you click a button, a message goes in the message queue; when the queue is pumped, the click handler corresponding to that message gets invoked.
It is therefore extremely common, and extremely dangerous, to write Windows programs where a lock contains a call to a method which pumps a message loop. If you got into that lock as a result of handling a message in the first place, and if the message is in the queue twice, then the code will enter itself indirectly, and that can cause all manner of craziness.
The way to eliminate this is (1) never do anything even slightly complicated inside a lock, and (2) when you are handling a message, disable the handler until the message is handled.
Re-Entrance is possible if you have a structure like so:
Object lockObject = new Object();
void Foo(bool recurse)
{
lock(lockObject)
{
Console.WriteLine("In Lock");
if (recurse) { foo(false); }
}
}
While this is a pretty simplistic example, it's possible in many scenarios where you have interdependent or recursive behaviour.
For example:
ComponentA.Add(): locks a common 'ComponentA' object, adds new item to ComponentB.
ComponentB.OnNewItem(): new item triggers data-validation on each item in list.
ComponentA.ValidateItem(): locks a common 'ComponentA' object to validate the item.
Same-thread re-entry on the same lock is needed to ensure you don't get deadlocks occurring with your own code.
One of the more subtle ways you can recurse into a lock block is in GUI frameworks. For example, you can asynchronously invoke code on a single UI thread (a Form class)
private object locker = new Object();
public void Method(int a)
{
lock (locker)
{
this.BeginInvoke((MethodInvoker) (() => Method(a)));
}
}
Of course, this also puts in an infinite loop; you'd likely have a condition by which you'd want to recurse at which point you wouldn't have an infinite loop.
Using lock is not a good way to sleep/awaken threads. I would simply use existing frameworks like Task Parallel Library (TPL) to simply create abstract tasks (see Task) to creates and the underlying framework handles creating new threads and sleeping them when needed.
IMHO, Re-entering a lock is not something you need to take care to avoid (given many people's mental model of locking this is, at best, dangerous, see Edit below). The point of the documentation is to explain that a thread cannot block itself using Monitor.Enter. This is not always the case with all synchronization mechanisms, frameworks, and languages. Some have non-reentrant synchronization in which case you have to be careful that a thread doesn't block itself. What you do need to be careful about is always calling Monitor.Exit for every Monitor.Enter call. The lock keyword does this for you automatically.
A trivial example with re-entrance:
private object locker = new object();
public void Method()
{
lock(locker)
{
lock(locker) { Console.WriteLine("Re-entered the lock."); }
}
}
The thread has entered the lock on the same object twice so it must be released twice. Usually it is not so obvious and there are various methods calling each other that synchronize on the same object. The point is that you don't have to worry about a thread blocking itself.
That said you should generally try to minimize the amount the time you need to hold a lock. Acquiring a lock is not computationally expensive, contrary to what you may hear (it is on the order of a few nanoseconds). Lock contention is what is expensive.
Edit
Please read Eric's comments below for additional details, but the summary is that when you see a lock your interpretation of it should be that "all activations of this code block are associated with a single thread", and not, as it is commonly interpreted, "all activations of this code block execute as a single atomic unit".
For example:
public static void Main()
{
Method();
}
private static int i = 0;
private static object locker = new object();
public static void Method()
{
lock(locker)
{
int j = ++i;
if (i < 2)
{
Method();
}
if (i != j)
{
throw new Exception("Boom!");
}
}
}
Obviously, this program blows up. Without the lock, it is the same result. The danger is that the lock leads you into a false sense of security that nothing could modify state on you between initializing j and evaluating the if. The problem is that you (perhaps unintentionally) have Method recursing into itself and the lock won't stop that. As Eric points out in his answer, you might not realize the problem until one day someone queues up too many actions simultaneously.
ThreadPool threads cannot be reused elsewhere just because they went to sleep; they need to finish before they're reused. A thread that is taking a long time in a lock region does not become eligible to run more code at some other independent point of control. The only way to experience lock re-entry is by recursion or executing methods or delegates inside a lock that re-enter the lock.
Let's think about something other than recursion.
In some of business logics, they would like to control the behaviors of synchronization.
One of these patterns, they invoke Monitor.Enter somewhere and would like to invoke Monitor.Exit elsewhere later. Here is the code to get the idea about that:
public partial class Infinity: IEnumerable<int> {
IEnumerator IEnumerable.GetEnumerator() {
return this.GetEnumerator();
}
public IEnumerator<int> GetEnumerator() {
for(; ; )
yield return ~0;
}
public static readonly Infinity Enumerable=new Infinity();
}
public partial class YourClass {
void ReleaseLock() {
for(; lockCount-->0; Monitor.Exit(yourLockObject))
;
}
void GetLocked() {
Monitor.Enter(yourLockObject);
++lockCount;
}
void YourParallelMethod(int x) {
GetLocked();
Debug.Print("lockCount={0}", lockCount);
}
public static void PeformTest() {
new Thread(
() => {
var threadCurrent=Thread.CurrentThread;
Debug.Print("ThreadId {0} starting...", threadCurrent.ManagedThreadId);
var intanceOfYourClass=new YourClass();
// Parallel.ForEach(Infinity.Enumerable, intanceOfYourClass.YourParallelMethod);
foreach(var i in Enumerable.Range(0, 123))
intanceOfYourClass.YourParallelMethod(i);
intanceOfYourClass.ReleaseLock();
Monitor.Exit(intanceOfYourClass.yourLockObject); // here SynchronizationLockException thrown
Debug.Print("ThreadId {0} finished. ", threadCurrent.ManagedThreadId);
}
).Start();
}
object yourLockObject=new object();
int lockCount;
}
If you invoke YourClass.PeformTest(), and get a lockCount greater than 1, you've reentered; not necessarily be concurrent.
If it was not safe for reentrancy, you will get stuck in the foreach loop.
In the code block where Monitor.Exit(intanceOfYourClass.yourLockObject) will throw you a SynchronizationLockException, it is because we are trying to invoke Exit more than the times it have entered. If you are about to use the lock keyword, you possibly would not encounter this situation except directly or indirectly of recursive calls. I guess that's why the lock keyword was provided: it prevents the Monitor.Exit to be omitted in a careless manner.
I remarked the calling of Parallel.ForEach, if you are interested then you can test it for fun.
To test the code, .Net Framework 4.0 is the least requirement, and following additional name spaces are required, too:
using System.Threading.Tasks;
using System.Diagnostics;
using System.Threading;
using System.Collections;
Have fun.

C# manual lock/unlock

I have a function in C# that can be called multiple times from multiple threads and I want it to be done only once so I thought about this:
class MyClass
{
bool done = false;
public void DoSomething()
{
lock(this)
if(!done)
{
done = true;
_DoSomething();
}
}
}
The problem is _DoSomething takes a long time and I don't want many threads to wait on it when they can just see that done is true.
Something like this can be a workaround:
class MyClass
{
bool done = false;
public void DoSomething()
{
bool doIt = false;
lock(this)
if(!done)
doIt = done = true;
if(doIt)
_DoSomething();
}
}
But just doing the locking and unlocking manually will be much better.
How can I manually lock and unlock just like the lock(object) does? I need it to use same interface as lock so that this manual way and lock will block each other (for more complex cases).
The lock keyword is just syntactic sugar for Monitor.Enter and Monitor.Exit:
Monitor.Enter(o);
try
{
//put your code here
}
finally
{
Monitor.Exit(o);
}
is the same as
lock(o)
{
//put your code here
}
Thomas suggests double-checked locking in his answer. This is problematic. First off, you should not use low-lock techniques unless you have demonstrated that you have a real performance problem that is solved by the low-lock technique. Low-lock techniques are insanely difficult to get right.
Second, it is problematic because we don't know what "_DoSomething" does or what consequences of its actions we are going to rely on.
Third, as I pointed out in a comment above, it seems crazy to return that the _DoSomething is "done" when another thread is in fact still in the process of doing it. I don't understand why you have that requirement, and I'm going to assume that it is a mistake. The problems with this pattern still exist even if we set "done" after "_DoSomething" does its thing.
Consider the following:
class MyClass
{
readonly object locker = new object();
bool done = false;
public void DoSomething()
{
if (!done)
{
lock(locker)
{
if(!done)
{
ReallyDoSomething();
done = true;
}
}
}
}
int x;
void ReallyDoSomething()
{
x = 123;
}
void DoIt()
{
DoSomething();
int y = x;
Debug.Assert(y == 123); // Can this fire?
}
Is this threadsafe in all possible implementations of C#? I don't think it is. Remember, non-volatile reads may be moved around in time by the processor cache. The C# language guarantees that volatile reads are consistently ordered with respect to critical execution points like locks, and it guarantees that non-volatile reads are consistent within a single thread of execution, but it does not guarantee that non-volatile reads are consistent in any way across threads of execution.
Let's look at an example.
Suppose there are two threads, Alpha and Bravo. Both call DoIt on a fresh instance of MyClass. What happens?
On thread Bravo, the processor cache happens to do a (non-volatile!) fetch of the memory location for x, which contains zero. "done" happens to be on a different page of memory which is not fetched into the cache quite yet.
On thread Alpha at the "same time" on a different processor DoIt calls DoSomething. Thread Alpha now runs everything in there. When thread Alpha is done its work, done is true and x is 123 on Alpha's processor. Thread Alpha's processor flushes those facts back out to main memory.
Thread bravo now runs DoSomething. It reads the page of main memory containing "done" into the processor cache and sees that it is true.
So now "done" is true, but "x" is still zero in the processor cache for thread Bravo. Thread Bravo is not required to invalidate the portion of the cache that contains "x" being zero because on thread Bravo neither the read of "done" nor the read of "x" were volatile reads.
The proposed version of double-checked locking is not actually double-checked locking at all. When you change the double-checked locking pattern you need to start over again from scratch and re-analyze everything.
The way to make this version of the pattern correct is to make at least the first read of "done" into a volatile read. Then the read of "x" will not be permitted to move "ahead" of the volatile read to "done".
You can check the value of done before and after the lock:
if (!done)
{
lock(this)
{
if(!done)
{
done = true;
_DoSomething();
}
}
}
This way you won't enter the lock if done is true. The second check inside the lock is to cope with race conditions if two threads enter the first if at the same time.
BTW, you shouldn't lock on this, because it can cause deadlocks. Lock on a private field instead (like private readonly object _syncLock = new object())
The lock keyword is just syntactic sugar for the Monitor class. Also you could call Monitor.Enter(), Monitor.Exit().
But the Monitor class itself has also the functions TryEnter() and Wait() which could help in your situation.
I know this answer comes several years late, but none of the current answers seem to address your actual scenario, which only became apparent after your comment:
The other threads don't need to use any information generated by ReallyDoSomething.
If the other threads don't need to wait for the operation to complete, the second code snippet in your question would work fine. You can optimize it further by eliminating your lock entirely and using an atomic operation instead:
private int done = 0;
public void DoSomething()
{
if (Interlocked.Exchange(ref done, 1) == 0) // only evaluates to true ONCE
_DoSomething();
}
Furthermore, if your _DoSomething() is a fire-and-forget operation, then you might not even need the first thread to wait for it, allowing it to run asynchronously in a task on the thread pool:
int done = 0;
public void DoSomething()
{
if (Interlocked.Exchange(ref done, 1) == 0)
Task.Factory.StartNew(_DoSomething);
}

Simple threading question, locking non local changes

Ok first I must preface this question with a disclaimer, I'm really new to threading so this may be a 'newbie' question but I searched google and couldn't find an answer. As I understand it a critical section is code that can be accessed by two or more threads, the danger being one thread will overwrite a value before the other is finished and vice versa. What can you do about changes made outside of your class for example, I have a line monitoring program:
int currentNumber = provider.GetCurrentNumber();
if(provider.CanPassNumber(false, currentNumber))
{
currentNumber++;
provider.SetNumber(currentNumber);
}
and on another thread I have something like this:
if(condition)
provider.SetNumber(numberToSet);
Now I'm afraid that in the first function I get currentNumber which is 5, right after that on another thread the number is set to 7 and then it rewrites the 7 to 6, ignoring the change made by the thread that set it to 7.
Is there anyway to lock provider.SetNumber until the first function finishes? The critical section is basically the currentNumber which can be changed by many places in the program.
I hope I made myself clear, if not let me know and I will try to explain myself better.
EDIT:
Also I made the functions really short for the example. In reality the function is much longer and makes changes to currentNumber many times so I don't really want to put a lock around the entire function. If I lock every call to provider.SetNumber and release it after I finish it can change during the time it is released before I lock it again to call provider.SetNumber. Honestly I'm also worried about locking the entire function because of performance and deadlock.
Rather than using the lock() keywords I'd suggested seeing if you can use the Interlocked class which is designed for small operations. It's got much less overhead than lock, in fact can be down to a single CPU instruction on some CPUs.
There are a couple of methods of interest for you, Exchange and Read, both of which are thread safe.
You want to look into the Lock keyword. Also you might want to this tutorial to Threading in C#.
As Filip said, lock is useful here.
Not only should you lock on provider.SetNumber(currentNumber), you also need to lock on any conditional that the setter depends on.
lock(someObject)
{
if(provider.CanPassNumber(false, currentNumber))
{
currentNumber++;
provider.SetNumber(currentNumber);
}
}
as well as
if(condition)
{
lock(someObject)
{
provider.SetNumber(numberToSet);
}
}
If condition is reliant on numberToSet, you should take the lock statement around the whole block. Also note that someObject must be the same object.
You can use the lock statement, to enter a critical section with mutual exclusion. The lock will use the object's reference to differentiate one critical section from another, you must have the same reference for all your lock if it accesses to the same elements.
// Define an object which can be locked in your class.
object locker = new object();
// Add around your critical sections the following :
lock (locker) { /* ... */ }
That will change your code to :
int currentNumber = provider.GetCurrentNumber();
lock (locker)
{
if(provider.CanPassNumber(false, currentNumber))
{
currentNumber++;
provider.SetNumber(currentNumber);
}
}
And :
if(condition)
{
lock (locker)
{
provider.SetNumber(numberToSet);
}
}
In your SetNumber method you can simply use a lock statement:
public class MyProvider {
object numberLock = new object();
...
public void SetNumber(int num) {
lock(numberLock) {
// Do Stuff
}
}
}
Also, note that in your example currentNumber is a primitive (int), which means that variable's value won't be overwritten should your provider's actual data member's value change.
Well first of im not so good with threading but a critical section is a part of your code that can only be accessed my one thread at a time not the other way around..
To create a critical section is easy
Lock(this)
{
//Only one thread can run this at a time
}
note: that this should be replaced with some internal object...

Categories

Resources