Imagine a situation in which there are one king and n number of minions submitted to him. When the king says "One!", one of the minions says "Two!", but only one of them. That is, only the fastest minion speaks while the others must wait for another call of the king.
This is my try:
using System;
using System.Threading;
class Program {
static bool leaderGO = false;
void Leader() {
do {
lock(this) {
//Console.WriteLine("? {0}", leaderGO);
if (leaderGO) Monitor.Wait(this);
Console.WriteLine("> One!");
Thread.Sleep(200);
leaderGO = true;
Monitor.Pulse(this);
}
} while(true);
}
void Follower (char chant) {
do {
lock(this) {
//Console.WriteLine("! {0}", leaderGO);
if (!leaderGO) Monitor.Wait(this);
Console.WriteLine("{0} Two!", chant);
leaderGO = false;
Monitor.Pulse(this);
}
} while(true);
}
static void Main() {
Console.WriteLine("Go!\n");
Program m = new Program();
Thread king = new Thread(() => m.Leader());
Thread minion1 = new Thread(() => m.Follower('#'));
Thread minion2 = new Thread(() => m.Follower('$'));
king.Start();
minion1.Start();
minion2.Start();
Console.ReadKey();
king.Abort();
minion1.Abort();
minion2.Abort();
}
}
The expected output would be this (# and $ representing the two different minions):
> One!
# Two!
> One!
$ Two!
> One!
$ Two!
...
The order in which they'd appear doesn't matter, it'd be random. The problem, however, is that this code, when compiled, produces this instead:
> One!
# Two!
$ Two!
> One!
# Two!
> One!
$ Two!
# Two!
...
That is, more than one minion speaks at the same time. This would cause quite the tumult with even more minions, and a king shouldn't allow a meddling of this kind.
What would be a possible solution?
For future readers, here's the final, working code:
using System;
using System.Threading;
class Program {
static AutoResetEvent leader = new AutoResetEvent(false);
static AutoResetEvent follower = new AutoResetEvent(false);
void Leader() {
do {
Console.WriteLine(" One!");
Thread.Sleep(300);
follower.Set(); // Leader allows a follower speak
leader.WaitOne(); // Leader waits for the follower to finish speaking
} while(true);
}
void Follower (char emblem) {
do {
follower.WaitOne(); // Follower waits for the leader to allow speaking
Console.WriteLine("{0} Two!", emblem);
leader.Set(); // Follower finishes speaking
} while(true);
}
static void Main() {
Console.WriteLine("Go!\n");
Program m = new Program();
Thread king = new Thread(() => m.Leader());
Thread minion1 = new Thread(() => m.Follower('#'));
Thread minion2 = new Thread(() => m.Follower('$'));
Thread minion3 = new Thread(() => m.Follower('&'));
king.Start();
minion1.Start();
minion2.Start();
minion3.Start();
Console.ReadKey();
king.Abort();
minion1.Abort();
minion2.Abort();
minion3.Abort();
}
}
Try using an AutoResetEvent instead of a lock/monitor. It allows you to create a "gate" that only one thread can get through at a time.
Your Follower() threads would call event.WaitOne() (optionally with a timeout). Your Leader() function would call event.Set(), which will release one of the waiting threads.
An AutoResetEvent (as opposed to other types of wait handles) will automatically "close the gate" once of the waiting threads is through.
http://msdn.microsoft.com/en-us/library/system.threading.autoresetevent.aspx
You aren't locking the followers down. So both threads are seeing leaderGo are true, and respond. Have the thread lock itself down before writing out, and that should fix it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace Threading
{
class Program
{
static bool leaderGO = false;
static bool followerGo = false;
void Leader()
{
do
{
lock (this)
{
//Console.WriteLine("? {0}", leaderGO);
if (leaderGO) Monitor.Wait(this);
Console.WriteLine("> One!");
Thread.Sleep(200);
leaderGO = true;
followerGo = true;
Monitor.Pulse(this);
}
} while (true);
}
void Follower(char chant)
{
do
{
lock (this)
{
//Console.WriteLine("! {0}", leaderGO);
if (!leaderGO) Monitor.Wait(this);
if(followerGo)
{
followerGo = false;
Console.WriteLine("{0} Two!", chant);
leaderGO = false;
}
Monitor.Pulse(this);
}
} while (true);
}
static void Main()
{
Console.WriteLine("Go!\n");
Program m = new Program();
Thread king = new Thread(() => m.Leader());
Thread minion1 = new Thread(() => m.Follower('#'));
Thread minion2 = new Thread(() => m.Follower('$'));
king.Start();
minion1.Start();
minion2.Start();
Console.ReadKey();
king.Abort();
minion1.Abort();
minion2.Abort();
}
}
}
What you're experiencing is a race condition. You have two separate threads operating on an unlocked resource (leaderGo), which controls their access to the critical section (printing out "Two!").
Placing a mutex lock (as recommended by manman) on leaderGo before printing out "Two!" is a start. You will also need to check to ensure that the value of leaderGo is still true before printing it, as both threads will eventually acquire the lock, but only one of them will acquire the lock while leaderGo is true.
Something like:
lock(leaderGo)
{
if (leaderGo)
Console.WriteLine("{0} Two!", chant);
leaderGo = false;
}
This will ensure only one follower is capable of responding (since it requires the lock). It will not guarantee which thread obtains the lock, the frequency at which specific threads obtain the lock, or anything like that. However, in each pass every thread will obtain the lock -- all that matters is who was first.
A few tips:
NEVER use lock(this). By locking the object from the inside, anything that uses your object as a locking focus will interfere with your own code's ability to synchronize.
NEVER use Thread.Abort(). It is evil; it kills your running threads by injecting an exception, which is unpredictable and thus difficult or impossible to catch and handle gracefully. Instead, try passing an instance of a class with a boolean property IsCancelled, and use !IsCancelled as the condition under which you keep looping.
The actual problem with your code is that your combination of Monitor and locks is causing the lock to be released from within the critical section by the thread that acquires the lock, if that thread thinks someone else must go first. You have three threads, each of which can acquire, then release and wait, before reacquiring the lock and proceeding as if the condition under which it waited was now false.
One possible scenario:
Follower 1 enters the critical section (lock() block) of Follower.
Follower 2 approaches the critical section of Follower and is told to wait.
King approaches the critical section of Leader and is told to wait.
Follower 1 sees that leaderGO is false and waits, releasing the lock on the critical section.
King, despite being second in line, "races" into the critical section ahead of Follower 2.
King continues (leaderGo is false so King never Wait()s), calls "One!" and sets the flag before releasing the lock at the end of the critical section.
Follower 2 now "races" into the critical section ahead of Follower 1, sees the flag is set, and continues, calling "Two!" and exiting the critical section.
Follower 1 now gets a turn, reacquiring the lock in the middle of its critical section. It no longer cares that leaderGo is false; it's past that check already. So, it continues, also calls "Two!", sets the flag (to the value it had already been) and exits.
There are many possible ways that these threads could "race" based on the way you have it set up.
Here's something that may work a little better; it's called double-checked locking, and while it isn't foolproof it's much better than what you have:
private static readonly object syncObj = new object();
void Leader() {
do {
if(leaderGo)
{
Thread.Sleep(200);
continue;
}
lock(syncObj) {
//the "double-check"; here it's not necessary because there's
//only one King to set leaderGo to true,
//but it doesn't hurt anything.
if(leaderGo) continue;
//we won't get here unless we have control of
//the critical section AND must do something.
Console.WriteLine("> One!");
Thread.Sleep(200);
leaderGO = true;
}
} while(true);
}
void Follower (char chant) {
do {
if(!leaderGo)
{
Thread.Yield();
continue;
}
lock(syncObj) {
//this double-check is critical;
//if we were waiting on the other follower to release
//the lock, they have already shouted out and we must not do so.
if (!leaderGO) continue;
//we only get here if we have
//control of the lock and should shout out
Console.WriteLine("{0} Two!", chant);
leaderGO = false;
}
} while(true);
}
EDIT: As mentioned in the comments, this model doesn't rely on luck, but it isn't foolproof because .NET, for performance, can allow several copies of leaderGO to exist in the caches of various threads, and synchronize them behind the scenes. If .NET isn't johnny-on-the-spot with that synchronization, the double-check performed by one thread may see the old, "stale" state of the flag and incorrectly move on when it should instead get out.
You can fix this one of two simple ways:
Put a MemoryBarrier just after any update of leaderGO, and just before any read of leaderGO. Memory barriers, or "memory fences" as they can be called in other languages, basically blocks each running thread at the memory barrier, until all threads are at a memory barrier (or blocked in other ways), ensuring that all instructions occurring before the memory barrier have been executed before any instructions after it are run.
Declare leaderGO as volatile. A volatile variable cannot be optimized by .NET; it is guaranteed to be in exactly one location in memory that is accessible, however inefficiently, by any thread that would run that code. Therefore any update to its value is immediately seen by any other thread.
Related
I'm starting a thread like this:
nameOfThread = new Thread(() =>
{
//do stuff
});
nameOfThread.Start();
At some point inside this anonymous function I open a WinSCP session like this:
using (Session session = new Session())
{
//do stuff
}
If I abort the thread (from somewhere else) like this nameOfThread.Abort() while still doing stuff inside using, is the session disposed at the end?
Most likely it will, but you can't be sure.
According to the documentation:
When this method [Abort] is invoked on a thread, the system throws a ThreadAbortException in the thread to abort it.
And we know exceptions will still let using statements dispose, as they should. (Give and take a few exceptions)
On the other hand, if you can end the thread gracefully, for example with a CancellationTokenSource, it would be a lot nicer for your app. It will offer much more control over the actual termination of your thread and the handling of exceptions.
I answered you can guarantee that the using statement will always call Dispose and I stand corrected, I was wrong.
There is a potential race condition with the using statement that doesn't guarantee disposing and I've put together a console app illustrating this (which isn't hard or trivial).
I was correct when showing how the IL generates using like so:
var session = new Session(); //If this causes an error or abort happens during initialization then we don't enter try
//If abort is called here then we never enter try
//In either case above we may have undisposed resources initialized at this point
try
{
//do stuff
}
finally
{
session.Dispose();
}
However; note the comments where I show the race condition that may occur if aborted before entering try.
Here is a console app written just to prove this point. The first works as expected but if you add the commented out code //thread.Abort() when we initialize R then you will see it init but never dispose :/
using System;
using System.Threading;
namespace Question_Answer_Console_App
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Start Main");
Thread thread = null;
thread = new Thread(new ThreadStart(() =>
{
Console.WriteLine("Thread Started");
using (var r = new R(thread))
{
Console.WriteLine($"Using {nameof(R)}");
}
}));
thread.Start();
thread.Join();
Console.WriteLine("End Main");
Console.ReadKey();
}
}
public class R : IDisposable
{
public R(Thread thread)
{
Console.WriteLine($"Init {nameof(R)}");
//thread.Abort();
}
public void Dispose()
{
Console.WriteLine($"Disposed {nameof(R)}");
}
}
}
Output with //thread.Abort() commented out:
Start Main
Thread Started
Init R
Using R
Disposed R
End Main
Output with thread.Abort() not commented out:
Start Main
Thread Started
Init R
End Main
I want to release all locked threads after one of them passes and complete the some task. Let me post some sample code about what I want to do. The important thing is they must pass all together after first thread completed his job. They(rest 99 threads) must be like that they have never locked not pass one by one.
Monitor.Enter(_lock);//imagine 100x threads hit this lock at same time.
//1 thread pass there
if (data == null)
{
data = GetData();
}
Monitor.Exit(_locker);//one more thread allow after this code.And they all come one by one in order.In these point I want to release them all together.
I have tried lots of class about threading like Monitor, Mutex, Semaphore, ReadWriteLock, ManaualResetEvent etc. but I didn't manage to do this, they all come one by one. Have you ever done this? Or Have you got ant idea about that? I don't wanna spent more time on it.
This might not be the most efficient way but it will work:
static SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
static CancellationTokenSource cts = new CancellationTokenSource();
static void CriticalSection()
{
if(!cts.Token.IsCancellationRequested)
{
try
{
semaphore.Wait(cts.Token);
}
catch (OperationCanceledException ) { }
}
/*
Critical section here
*/
if(!cts.Token.IsCancellationRequested)
cts.Cancel();
}
the SemaphoreSlim will only let 1 thread run the "critical section". After the first thread is over with the section it will cancel the token. This will lead into an OperationCanceledException as described here. All the threads that were waiting will throw the exception that will be catched in the "try catch statement" and then execute the critical section. The first "if statement" is to check the state of the token to avoid the wait and throw pattern if it has been cancelled in the past.
The performance hit will be on the first time you have your threads "released" from the wait since they will all throw an exception. Later on, the only impact is going to be around the cancellation token check and the general maintainability of your code.
static SemaphoreSlim semaphore = new SemaphoreSlim(1);
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(LoadDataPart);
t.Name = (i + 1).ToString();
t.Start();
}
Console.Read();
}
static void LoadDataPart()
{
Console.WriteLine("Before Wait {0}", Thread.CurrentThread.Name);
semaphore.Wait();
Console.WriteLine("After Wait {0}", Thread.CurrentThread.Name);
Thread.Sleep(3000);
Console.WriteLine("Done {0}", Thread.CurrentThread.Name);
semaphore.Release(10);//this line must be changed,its allow too much thread coz its called 10 times!
}
I can manage what I want to do like this. In this code sample 10 threads hit wait. 9 of them waited other one keep going. When 1 thread done his job other 9 goes together not one by one. To check that I put thread sleep and all threads complated in 6 sec not in 30 secs. Now I can customize my code.
I have a Thread (STAThread) in a Windows Service, which performs a big amount of work. When the windows service is restarted I want to stop this thread gracefully.
I know of a couple of ways
A volatile boolean
ManualResetEvent
CancellationToken
As far as I have found out Thread.Abort is a no go...
What is the best practice ?
The work is perfomed in another class than the one where the thread is started, so it is necessary to either introduce a cancellationToken parameter in a constructor or for example have a volatile variable. But I just can't figure out what is smartest.
Update
Just to clarify a little I have wrapped up a very simple example of what I'm talking about. As said earlier, this is being done in a windows service. Right now I'm thinking a volatile boolean that is checked on in the loop or a cancellationToken....
I cannot wait for the loop to finish, as stated below it can take several minutes, making the system administrators of the server believe that something is wrong with the service when they need to restart it.... I can without problems just drop all the work within the loop without problems, however I cannot do this with a Thread.Abort it is "evil" and furthermore a COM interface is called, so a small clean up is needed.
Class Scheduler{
private Thread apartmentThread;
private Worker worker;
void Scheduling(){
worker = new Worker();
apartmentThread = new Thread(Run);
apartmentThread.SetApartmentState(ApartmentState.STA);
apartmentThread.Start();
}
private void Run() {
while (!token.IsCancellationRequested) {
Thread.Sleep(pollInterval * MillisecondsToSeconds);
if (!token.IsCancellationRequested) {
worker.DoWork();
}
}
}
}
Class Worker{
//This will take several minutes....
public void DoWork(){
for(int i = 0; i < 50000; i++){
//Do some work including communication with a COM interface
//Communication with COM interface doesn't take long
}
}
}
UPDATE
Just examined performance, using a cancellationToken where the isCancelled state is "examined" in the code, is much faster than using a waitOne on a ManualResetEventSlim. Some quick figuers, an if on the cancellationToken iterating 100.000.000 times in a for loop costs me approx. 500 ms, where the WaitOne costs approx. 3 seconds. So performance in this scenario it is faster to use the cancellationToken.
You haven't posted enough of your implementation but I would highly recommend a CancellationToken if that is available to you. It's simple enough to use and understand from a maintainability standpoint. You can setup cooperative cancellation as well too if you decide to have more than one worker thread.
If you find yourself in a situation where this thread may block for long periods of time, it's best to setup your architecture so that this doesn't occur. You shouldn't be starting threads that won't play nice when you tell them to stop. If they don't stop when you ask them, the only real way is to tear down the process and let the OS kill them.
Eric Lippert posted a fantastic answer to a somewhat-related question here.
I tend to use a bool flag, a lock object and a Terminate() method, such as:
object locker = new object();
bool do_term = false;
Thread thread = new Thread(ThreadStart(ThreadProc));
thread.Start();
void ThreadProc()
{
while (true) {
lock (locker) {
if (do_term) break;
}
... do work...
}
}
void Terminate()
{
lock (locker) {
do_term = true;
}
}
Asides from Terminate() all the other fields and methods are private to the "worker" class.
Use a WaitHandle, most preferably a ManualResetEvent. Your best bet is to let whatever is in your loop finish. This is the safest way to accomplish your goal.
ManualResetEvent _stopSignal = new ManualResetEvent(false); // Your "stopper"
ManualResetEvent _exitedSignal = new ManualResetEvent(false);
void DoProcessing() {
try {
while (!_stopSignal.WaitOne(0)) {
DoSomething();
}
}
finally {
_exitedSignal.Set();
}
}
void DoSomething() {
//Some work goes here
}
public void Terminate() {
_stopSignal.Set();
_exitedSignal.WaitOne();
}
Then to use it:
Thread thread = new Thread(() => { thing.DoProcessing(); });
thread.Start();
//Some time later...
thing.Terminate();
If you have a particularly long-running process in your "DoSomething" implementation, you may want to call that asynchronously, and provide it with state information. That can get pretty complicated, though -- better to just wait until your process is finished, then exit, if you are able.
There are two situations in which you may find your thread:
Processing.
Blocking.
In the case where your thread is processing something, you must wait for your thread to finish processing in order for it to safely exit. If it's part of a work loop, then you can use a boolean flag to terminate the loop.
In the case where your thread is blocking, then you need to wake your thread and get it processing again. A thread may be blocking on a ManualResetEvent, a database call, a socket call or whatever else you could block on. In order to wake it up, you must call the Thread.Interrupt() method which will raise a ThreadInterruptedException.
It may look something like this:
private object sync = new object():
private bool running = false;
private void Run()
{
running = true;
while(true)
{
try
{
lock(sync)
{
if(!running)
{
break;
}
}
BlockingFunction();
}
catch(ThreadInterruptedException)
{
break;
}
}
}
public void Stop()
{
lock(sync)
{
running = false;
}
}
And here is how you can use it:
MyRunner r = new MyRunner();
Thread t = new Thread(()=>
{
r.Run();
});
t.IsBackground = true;
t.Start();
// To stop the thread
r.Stop();
// Interrupt the thread if it's in a blocking state
t.Interrupt();
// Wait for the thread to exit
t.Join();
super simple question, but I just wanted some clarification. I want to be able to restart a thread using AutoResetEvent, so I call the following sequence of methods to my AutoResetEvent.
setupEvent.Reset();
setupEvent.Set();
I know it's really obvious, but MSDN doesn't state in their documentation that the Reset method restarts the thread, just that it sets the state of the event to non-signaled.
UPDATE:
Yes the other thread is waiting at WaitOne(), I'm assuming when it gets called it will resume at the exact point it left off, which is what I don't want, I want it to restart from the beginning. The following example from this valuable resource illustrates this:
static void Main()
{
new Thread (Work).Start();
_ready.WaitOne(); // First wait until worker is ready
lock (_locker) _message = "ooo";
_go.Set(); // Tell worker to go
_ready.WaitOne();
lock (_locker) _message = "ahhh"; // Give the worker another message
_go.Set();
_ready.WaitOne();
lock (_locker) _message = null; // Signal the worker to exit
_go.Set();
}
static void Work()
{
while (true)
{
_ready.Set(); // Indicate that we're ready
_go.WaitOne(); // Wait to be kicked off...
lock (_locker)
{
if (_message == null) return; // Gracefully exit
Console.WriteLine (_message);
}
}
}
If I understand this example correctly, notice how the Main thread will resume where it left off when the Work thread signals it, but in my case, I would want the Main thread to restart from the beginning.
UPDATE 2:
#Jaroslav Jandek - It's quite involved, but basically I have a CopyDetection thread that runs a FileSystemWatcher to monitor a folder for any new files that are moved or copied into it. My second thread is responsible for replicating the structure of that particular folder into another folder. So my CopyDetection thread has to block that thread from working while a copy/move operation is in progress. When the operation completes, the CopyDetection thread restarts the second thread so it can re-duplicate the folder structure with the newly added files.
UPDATE 3:
#SwDevMan81 - I actually didn't think about that and that would work save for one caveat. In my program, the source folder that is being duplicated is emptied once the duplication process is complete. That's why I have to block and restart the second thread when new items are added to the source folder, so it can have a chance to re-parse the folder's new structure properly.
To address this, I'm thinking of maybe adding a flag that signals that it is safe to delete the source folder's contents. Guess I could put the delete operation on it's own Cleanup thread.
#Jaroslav Jandek - My apologies, I thought it would be a simple matter to restart a thread on a whim. To answer your questions, I'm not deleting the source folder, only it's content, it's a requirement by my employer that unfortunately I cannot change. Files in the source folder are getting moved, but not all of them, only files that are properly validated by another process, the rest must be purged, i.e. the source folder is emptied. Also, the reason for replicating the source folder structure is that some of the files are contained within a very strict sub-folder hierarchy that must be preserved in the destination directory. Again sorry for making it complicated. All of these mechanisms are in place, have been tested and are working, which is why I didn't feel the need to elaborate on them. I only need to detect when new files are added so I may properly halt the other processes while the copy/move operation is in progress, then I can safely replicate the source folder structure and resume processing.
So thread 1 monitors and thread 2 replicates while other processes modify the monitored files.
Concurrent file access aside, you can't continue replicating after a change. So a successful replication only occurs when there is long enough delay between modifications. Replication cannot be stopped immediately since you replicate in chunks.
So the result of monitoring should be a command (file copy, file delete, file move, etc.).
The result of a successful replication should be an execution of a command.
Considering multiple operations can occur, you need a queue (or queued dictionary - to only perform 1 command on a file) of commands.
// T1:
somethingChanged(string path, CT commandType)
{
commandQueue.AddCommand(path, commandType);
}
// T2:
while (whatever)
{
var command = commandQueue.Peek();
if (command.Execute()) commandQueue.Remove();
else // operation failed, do what you like.
}
Now you may ask how to create a thread-safe query, but that probably belongs to another question (there are many implementations on the web).
EDIT (queue-less version with whole dir replication - can be used with query):
If you do not need multiple operations (eg. always replication the whole directory) and expect the replication to always finish or fail and cancel, you can do:
private volatile bool shouldStop = true;
// T1:
directoryChanged()
{
// StopReplicating
shouldStop = true;
workerReady.WaitOne(); // Wait for the worker to stop replicating.
// StartReplicating
shouldStop = false;
replicationStarter.Set();
}
// T2:
while (whatever)
{
replicationStarter.WaitOne();
... // prepare, throw some shouldStops so worker does not have to work too much.
if (!shouldStop)
{
foreach (var file in files)
{
if (shouldStop) break;
// Copy the file or whatever.
}
}
workerReady.Set();
}
I think this example clarifies (to me anyway) how reset events work:
var resetEvent = new ManualResetEvent(false);
var myclass = new MyAsyncClass();
myclass.MethodFinished += delegate
{
resetEvent.Set();
};
myclass.StartAsyncMethod();
resetEvent.WaitOne(); //We want to wait until the event fires to go on
Assume that MyAsyncClass runs the method on a another thread and fires the event when complete.
This basically turns the asynchronous "StartAsyncMethod" into a synchronous one. Many times I find a real-life example more useful.
The main difference between AutoResetEvent and ManualResetEvent, is that using AutoResetEvent doesn't require you to call Reset(), but automatically sets the state to "false". The next call to WaitOne() blocks when the state is "false" or Reset() has been called.
You just need to make it loop like the other Thread does. Is this what you are looking for?
class Program
{
static AutoResetEvent _ready = new AutoResetEvent(false);
static AutoResetEvent _go = new AutoResetEvent(false);
static Object _locker = new Object();
static string _message = "Start";
static AutoResetEvent _exitClient = new AutoResetEvent(false);
static AutoResetEvent _exitWork = new AutoResetEvent(false);
static void Main()
{
new Thread(Work).Start();
new Thread(Client).Start();
Thread.Sleep(3000); // Run for 3 seconds then finish up
_exitClient.Set();
_exitWork.Set();
_ready.Set(); // Make sure were not blocking still
_go.Set();
}
static void Client()
{
List<string> messages = new List<string>() { "ooo", "ahhh", null };
int i = 0;
while (!_exitClient.WaitOne(0)) // Gracefully exit if triggered
{
_ready.WaitOne(); // First wait until worker is ready
lock (_locker) _message = messages[i++];
_go.Set(); // Tell worker to go
if (i == 3) { i = 0; }
}
}
static void Work()
{
while (!_exitWork.WaitOne(0)) // Gracefully exit if triggered
{
_ready.Set(); // Indicate that we're ready
_go.WaitOne(); // Wait to be kicked off...
lock (_locker)
{
if (_message != null)
{
Console.WriteLine(_message);
}
}
}
}
}
I have scenarios where I need a main thread to wait until every one of a set of possible more than 64 threads have completed their work, and for that I wrote the following helper utility, (to avoid the 64 waithandle limit on WaitHandle.WaitAll())
public static void WaitAll(WaitHandle[] handles)
{
if (handles == null)
throw new ArgumentNullException("handles",
"WaitHandle[] handles was null");
foreach (WaitHandle wh in handles) wh.WaitOne();
}
With this utility method, however, each waithandle is only examined after every preceding one in the array has been signalled... so it is in effect synchronous, and will not work if the waithandles are autoResetEvent wait handles (which clear as soon as a waiting thread has been released)
To fix this issue I am considering changing this code to the following, but would like others to check and see if it looks like it will work, or if anyone sees any issues with it, or can suggest a better way ...
Thanks in advance:
public static void WaitAllParallel(WaitHandle[] handles)
{
if (handles == null)
throw new ArgumentNullException("handles",
"WaitHandle[] handles was null");
int actThreadCount = handles.Length;
object locker = new object();
foreach (WaitHandle wh in handles)
{
WaitHandle qwH = wh;
ThreadPool.QueueUserWorkItem(
delegate
{
try { qwH.WaitOne(); }
finally { lock(locker) --actThreadCount; }
});
}
while (actThreadCount > 0) Thread.Sleep(80);
}
If you know how many threads you have, you can use an interlocked decrement. This is how I usually do it:
{
eventDone = new AutoResetEvent();
totalCount = 128;
for(0...128) {ThreadPool.QueueUserWorkItem(ThreadWorker, ...);}
}
void ThreadWorker(object state)
try
{
... work and more work
}
finally
{
int runningCount = Interlocked.Decrement(ref totalCount);
if (0 == runningCount)
{
// This is the last thread, notify the waiters
eventDone.Set();
}
}
Actually, most times I don't even signal but instead invoke a callback continues the processing from where the waiter would continue. Less blocked threads, more scalability.
I know is different and may not apply to your case (eg. for sure will not work if some of thoe handles are not threads, but I/O or events), but it may worth thinking about this.
I'm not sure what exactly you're trying to do, but would a CountdownEvent (.NET 4.0) conceptually solve your problem?
I'm not a C# or .NET programmer, but you could use a semaphore that is posted when one of your worker threads exits. The monitoring thread would simply wait on the semaphore n times where n is the number of worker threads. Semaphores are traditionally used to count resources in use but they can be used to count jobs completed by waiting on the same semaphore for n times.
When working with lots of simultaneous threads, I prefer to add each thread's ManagedThreadId into a Dictionary when I start the thread, and then have each thread invoke a callback routine that removes the dying thread's id from the Dictionary. The Dictionary's Count property tells you how many threads are active. Use the value side of the key/value pair to hold info that your UI thread can use to report status. Wrap the Dictionary with a lock to keep things safe.
ThreadPool.QueueUserWorkItem(o =>
{
try
{
using (var h = (o as WaitHandle))
{
if (!h.WaitOne(100000))
{
// Alert main thread of the timeout
}
}
}
finally
{
Interlocked.Decrement(ref actThreadCount);
}
}, wh);