C#: Synchronizing threads in a particular order [duplicate] - c#

I have three threads and some part of the code can run in parallel, some parts are locked(only one thread at the time). However one lock needs to only let them in in order. Since this is a loop it gets more complex. How do I make this behavior?
If i had a print statement I would like to receive the following output:
1,2,3,1,2,3,1,2,3.... currently I receive 2,3,1,3,1,3,2,1,2 A.K.A. random order.
The code which is executed in three threads in parallel:
while (true){
lock (fetchLock){
if(done){
break;
}
//Do stuff one at the time
}
//Do stuff in parralell
lock (displayLock){
//Do stuff one at the time but need's to be in order.
}
}

You could use a combination of Barrier and AutoResetEvent to achieve this.
Firstly, you use Barrier.SignalAndWait() to ensure that all the threads reach a common point before proceeding. This common point is the point at which you want the threads to execute some code in order.
Then you use numberOfThreads-1 AutoResetEvents to synchronise the threads. The first thread doesn't need to wait for any other thread, but after it has finished it should signal the event that the next thread is waiting on.
The middle thread (or threads if more than 3 threads total) needs to wait for the previous thread to signal the event that tells it to proceed. After it has finished, the middle thread should signal the event that the next thread is waiting on.
The last thread needs to wait for the previous thread to signal the event that tells it to proceed. Since it is the last thread, it does not need to signal an event to tell the next thread to proceed.
Finally, you resync the threads with another call to Barrier.SignalAndWait().
This is easiest to show via a sample console app. If you run it, you'll see that the work that should be done by the threads in order (prefixed with the letter "B" in the output) is indeed always in order, while the other work (prefixed with the letter "A") is executed in a random order.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Demo
{
public static class Program
{
public static void Main()
{
using (Barrier barrier = new Barrier(3))
using (AutoResetEvent t2 = new AutoResetEvent(false))
using (AutoResetEvent t3 = new AutoResetEvent(false))
{
Parallel.Invoke
(
() => worker(1, barrier, null, t2),
() => worker(2, barrier, t2, t3),
() => worker(3, barrier, t3, null)
);
}
}
private static void worker(int threadId, Barrier barrier, AutoResetEvent thisThreadEvent, AutoResetEvent nextThreadEvent)
{
Random rng = new Random(threadId);
for (int i = 0; i < 1000; ++i)
{
doSomething(threadId, rng); // We don't care what order threads execute this code.
barrier.SignalAndWait(); // Wait for all threads to reach this point.
if (thisThreadEvent != null) // If this thread is supposed to wait for a signal
thisThreadEvent.WaitOne(); // before proceeding, then wait for it.
doWorkThatMustBeDoneInThreadOrder(threadId);
if (nextThreadEvent != null) // If this thread is supposed to raise a signal to indicate
nextThreadEvent.Set(); // that the next thread should proceed, then raise it.
barrier.SignalAndWait(); // Wait for all threads to reach this point.
}
}
private static void doWorkThatMustBeDoneInThreadOrder(int threadId)
{
Console.WriteLine(" B" + threadId);
Thread.Sleep(200); // Simulate work.
}
private static void doSomething(int threadId, Random rng)
{
for (int i = 0; i < 5; ++i)
{
Thread.Sleep(rng.Next(50)); // Simulate indeterminate amount of work.
Console.WriteLine("A" + threadId);
}
}
}
}

Related

Will all the worker threads get generated at once?

Is anyone out there who can explain me the flow of this code?
I wonder how main thread generates worker threads, what I know is:
As soon as main thread calls .start method it creates a new thread.
But I have a confusion how the behavior changes when it comes to looping multiple threads in main.
static void Main()
{
Thread[] tr = new Thread[10];
for (int i = 0; i < 10; i++)
{
tr[i] = new Thread(new ThreadStart(count));
tr[i].Start();
}
static private void count()
{
for (int i = 0; i < 10; ++i)
{
lock (theLock)
{
Console.WriteLine("Count {0} Thread{1}",
counter++, Thread.CurrentThread.GetHashCode());
}
}
Is there a good way to debug and track your multithreaded program. after google it out I found tracking thread window in debug mood, but I couldn't find it useful even after given custom names to threads.
I just can't understand the flow, how threads being launched, how they work all together etc as breakpoints seem no effect in multi-threaded application. (At least in my case.)
I want this output 1 printed by Thread : 4551 [ThreadID] 2 printed by
Thread : 4552 3 printed by Thread : 4553 4 printed by Thread : 4554 5
printed by Thread : 4555 6 printed by Thread : 4556 7 printed by
Thread : 4557 8 printed by Thread : 4558 9 printed by Thread : 4559 10
printed by Thread : 4560 11 printed by Thread : 4551 [ Same Thread Id
Appears again as in 1] 12 printed by Thread : 4552
I'll try to describe what your code is doing as it interacts with the threading subsystem. The details I'm giving are from what I remember from my OS design university classes, so the actual implementation in the host operating system and/or the CLR internals may vary a bit from what I describe.
static void Main()
{
Thread[] tr = new Thread[10];
for (int i = 0; i < 10; i++)
{
tr[i] = new Thread(new ThreadStart(count));
// The following line puts the thread in a "runnable" thread list that is
// managed by the OS scheduler. The scheduler will allow threads to run by
// considering many factors, such as how many processes are running on
// the system, how much time a runnable thread has been waiting, the process
// priority, the thread's priority, etc. This means you have little control
// on the order of execution, The only certain fact is that your thread will
// run, at some point in the near future.
tr[i].Start();
// At this point you are exiting your main function, so the program should
// end, however, since you didn't flag your threads as BackgroundThreads,
// the program will keep running until every thread finishes.
}
static private void count()
{
// The following loop is very short, and it is probable that the thread
// might finish before the scheduler allows another thread to run
// Like user2864740 suggested, increasing the amount of iterations will
// increase the chance that you experience interleaved execution between
// multiple threads
for (int i = 0; i < 10; ++i)
{
// Acquire a mutually-exclusive lock on theLock. Assuming that
// theLock has been declared static, then only a single thread will be
// allowed to execute the code guarded by the lock.
// Any running thread that tries to acquire the lock that is
// being held by a different thread will BLOCK. In this case, the
// blocking operation will do the following:
// 1. Register the thread that is about to be blocked in the
// lock's wait list (this is managed by a specialized class
// known as the Monitor)
// 2. Remove the thread that is about to be blocked from the scheduler's
// runnable list. This way the scheduler won't try to yield
// the CPU to a thread that is waiting for a lock to be
// released. This saves CPU cycles.
// 3. Yield execution (allow other threads to run)
lock (theLock)
{
// Only a single thread can run the following code
Console.WriteLine("Count {0} Thread{1}",
counter++, Thread.CurrentThread.GetHashCode());
}
// At this point the lock is released. The Monitor class will inspect
// the released lock's wait list. If any threads were waiting for the
// lock, one of them will be selected and returned to the scheduler's
// runnable list, where eventually it will be given the chance to run
// and contend for the lock. Again, many factors may be evaluated
// when selecting which blocked thread to return to the runnable
// list, so we can't make any guarantees on the order the threads
// are unblocked
}
}
Hopefully things are clearer. The important thing here is to acknowledge that you have little control of how individual threads are scheduled for execution, making it impossible (without a fair amount of synchronization code) to replicate the output you are expecting. At most, you can change a thread's priority to hint the scheduler that a certain thread must be favored over other threads. However, this needs to be done very carefully, as it may lead to a nasty problem known as priority inversion. Unless you know exactly what you are doing, it is usually better not to change a thread's priority.
After a continuous try, I got to complete the requirements of my task. Here is the code:
using System;
using System.Threading;
public class EntryPoint
{
static private int counter = 0;
static private object theLock = new Object();
static object obj = new object();
static private void count()
{
{
for (int i = 0; i < 10; i++)
{
lock (theLock)
{
Console.WriteLine("Count {0} Thread{1}",
counter++, Thread.CurrentThread.GetHashCode());
if (counter>=10)
Monitor.Pulse(theLock);
Monitor.Wait(theLock); } }}
}
static void Main()
{
Thread[] tr = new Thread[10];
for (int i = 0; i < 10; i++)
{
tr[i] = new Thread(new ThreadStart(count));
tr[i].Start();
}
}
}
Monitor maintains a ready queue in a sequential order hence I achieved what I wanted:
Cheers!

Implementing a thread queue/wait, how?

I have a timer calling a function every 15 minutes, this function counts the amount of lines in my DGV and starts a thread for each lines (of yet another function), said thread parse a web page which can take anywhere from 1 second to 10 second to finish.
Whilst it does work fine as it is with 1-6 rows, anymore will cause the requests to time-out.
I want it to wait for the newly created thread to finish processing before getting back in the loop to create another thread without locking the main UI
for (int x = 0; x <= dataGridFollow.Rows.Count - 1; x++)
{
string getID = dataGridFollow.Rows[x].Cells["ID"].Value.ToString();
int ID = int.Parse(getID);
Thread t = new Thread(new ParameterizedThreadStart(UpdateLo));
t.Start(ID);
// <- Wait for thread to finish here before getting back in the for loop
}
I have googled a lot in the past 24 hours, read a lot about this specific issue and its implementations (Thread.Join, ThreadPools, Queuing, and even SmartThreadPool).
It's likely that I've read the correct answer somewhere but I'm not at ease enough with C# to decypher those Threading tools
Thanks for your time
to avoid the UI freeze the framework provide a class expressly for these purposes: have a look at the BackgroundWorker class (executes an operation on a separate thread), here's some infos : http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
http://msdn.microsoft.com/en-us/magazine/cc300429.aspx
Btw looks if I understand correctly you don't want to parallelize any operation so just wait for the method parsing the page to be completed. Basically for each (foreach look) row of your grid you get the id and call the method. If you want to go parallel just reuse the same foreach loop and add make it Parallel
http://msdn.microsoft.com/en-us/library/dd460720.aspx
What you want is to set off a few workers that do some task.
When one finishes you can start a new one off.
I'm sure there is a better way using thread pools or whatever.. but I was bored so i came up with this.
using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
using System.Threading;
namespace WorkerTest
{
class Program
{
static void Main(string[] args)
{
WorkerGroup workerGroup = new WorkerGroup();
Console.WriteLine("Starting...");
for (int i = 0; i < 100; i++)
{
var work = new Action(() =>
{
Thread.Sleep(1000); //somework
});
workerGroup.AddWork(work);
}
while (workerGroup.WorkCount > 0)
{
Console.WriteLine(workerGroup.WorkCount);
Thread.Sleep(1000);
}
Console.WriteLine("Fin");
Console.ReadLine();
}
}
public class WorkerGroup
{
private List<Worker> workers;
private Queue<Action> workToDo;
private object Lock = new object();
public int WorkCount { get { return workToDo.Count; } }
public WorkerGroup()
{
workers = new List<Worker>();
workers.Add(new Worker());
workers.Add(new Worker());
foreach (var w in workers)
{
w.WorkCompleted += (OnWorkCompleted);
}
workToDo = new Queue<Action>();
}
private void OnWorkCompleted(object sender, EventArgs e)
{
FindWork();
}
public void AddWork(Action work)
{
workToDo.Enqueue(work);
FindWork();
}
private void FindWork()
{
lock (Lock)
{
if (workToDo.Count > 0)
{
var availableWorker = workers.FirstOrDefault(x => !x.IsBusy);
if (availableWorker != null)
{
var work = workToDo.Dequeue();
availableWorker.StartWork(work);
}
}
}
}
}
public class Worker
{
private BackgroundWorker worker;
private Action work;
public bool IsBusy { get { return worker.IsBusy; } }
public event EventHandler WorkCompleted;
public Worker()
{
worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(OnWorkerDoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(OnWorkerRunWorkerCompleted);
}
private void OnWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (WorkCompleted != null)
{
WorkCompleted(this, EventArgs.Empty);
}
}
public void StartWork(Action work)
{
if (!IsBusy)
{
this.work = work;
worker.RunWorkerAsync();
}
else
{
throw new InvalidOperationException("Worker is busy");
}
}
private void OnWorkerDoWork(object sender, DoWorkEventArgs e)
{
work.Invoke();
work = null;
}
}
}
This would be just a starting point.
You could start it off with a list of Actions and then have a completed event for when that group of actions is finished.
then at least you can use a ManualResetEvent to wait for the completed event.. or whatever logic you want really.
Call a method directly or do a while loop (with sleep calls) to check the status of the thread.
There are also async events but the would call another method, and you want to continue from the same point.
I have no idea why the requests would timeout. That sounds like a different issue. However, I can make a few suggestions regarding your current approach.
Avoid creating threads in loops with nondeterministic bounds. There is a lot of overhead in creating threads. If the number of operations is not known before hand then use the ThreadPool or the Task Parallel Library instead.
You are not going to get the behavior you want by blocking the UI thread with Thread.Join. The cause the UI to become unresponsive and it will effectively serialize the operations and cancel out any advantage you were hoping to gain with threads.
If you really want to limit the number of concurrent operations then a better solution is to create a separate dedicated thread for kicking off the operations. This thread will spin around a loop indefinitely waiting for items to appear in a queue and when they do it will dequeue them and use that information to kick off an operation asynchronously (again using the ThreadPool or TPL). The dequeueing thread can contain the logic for limiting the number of concurrent operations. Search for information regarding the producer-consumer pattern to get a better understand of how you can implement this.
There is a bit of a learning curve, but who said threading was easy right?
If I understand correctly, what you're currently doing is looping through a list of IDs in the UI thread, starting a new thread to handle each one. The blocking issue you're seeing then could well be that it's taking too many resources to create unique threads. So, personally (without knowing more) would redesign the process like so:
//Somewhere in the UI Thread
Thread worker = new Thread(new ParameterizedThreadStart(UpdateLoWorker));
worker.Start(dataGridFollow.Rows);
//worker thread
private void UpdateLoWorker(DataRowCollection rows)
{
foreach(DataRow r in rows){
string getID = r.Cells["ID"].Value.ToString();
int ID = int.Parse(getID);
UpdateLo(ID);
}
}
Here you'd have a single non-blocking worker which sequentially handles each ID.
Consider using Asynchronous CTP. It's an asynch pattern Microsoft recently released for download. It should simplify asynch programming tremendouesly. The link is http://msdn.microsoft.com/en-us/vstudio/async.aspx. (Read the whitepaper first)
Your code would look something like the following. (I've not verified my syntax yet, sorry).
private async Task DoTheWork()
{
for(int x = 0; x <= dataGridFollow.Rows.Count - 1; x++)
{
string getID = dataGridFollow.Rows[x].Cells["ID"].Value.ToString();
int ID = int.Parse(getID);
task t = new Task(new Action<object>(UpdateLo), ID);
t.Start();
await t;
}
}
This method returns a Task that can be checked periodically for completion. This follows the pattern of "fire and forget" meaning you just call it and presumably, you don't care when it completes (as long as it does complete before 15 minutes).
EDIT
I corrected the syntax above, you would need to change UpdateLo to take an object instead of an Int.
For a simple background thread runner that will run one thread from a queue at a time you can do something like this:
private List<Thread> mThreads = new List<Thread>();
public static void Main()
{
Thread t = new Thread(ThreadMonitor);
t.IsBackground = true;
t.Start();
}
private static void ThreadMonitor()
{
while (true)
{
foreach (Thread t in mThreads.ToArray())
{
// Runs one thread in the queue and waits for it to finish
t.Start();
mThreads.Remove(t);
t.Join();
}
Thread.Sleep(2000); // Wait before checking for new threads
}
}
// Called from the UI or elsewhere to create any number of new threads to run
public static void DoStuff()
{
Thread t = new Thread(DoCorestuff);
t.IsBackground = true;
mActiveThreads.Add(t);
}
public static void DoStuffCore()
{
// Your code here
}

Thread signaling basics

In C# how does one achieve thread signaling?
Here is a custom-made console application example for you. Not really a good real world scenario, but the usage of thread signaling is there.
using System;
using System.Threading;
class Program
{
static void Main()
{
bool isCompleted = false;
int diceRollResult = 0;
// AutoResetEvent is one type of the WaitHandle that you can use for signaling purpose.
AutoResetEvent waitHandle = new AutoResetEvent(false);
Thread thread = new Thread(delegate() {
Random random = new Random();
int numberOfTimesToLoop = random.Next(1, 10);
for (int i = 0; i < numberOfTimesToLoop - 1; i++) {
diceRollResult = random.Next(1, 6);
// Signal the waiting thread so that it knows the result is ready.
waitHandle.Set();
// Sleep so that the waiting thread have enough time to get the result properly - no race condition.
Thread.Sleep(1000);
}
diceRollResult = random.Next(1, 6);
isCompleted = true;
// Signal the waiting thread so that it knows the result is ready.
waitHandle.Set();
});
thread.Start();
while (!isCompleted) {
// Wait for signal from the dice rolling thread.
waitHandle.WaitOne();
Console.WriteLine("Dice roll result: {0}", diceRollResult);
}
Console.Write("Dice roll completed. Press any key to quit...");
Console.ReadKey(true);
}
}
The way this works in a nutshell.
AutoResetEvent waitHandle = new AutoResetEvent(false); --- The false means that that wait handle is unsignaled if a waitHandle.WaitOne() is called it will stop the thread.
The thread you want to wait for another event to complete add
waitHandle.WaitOne();
In the thread that needs to be completed,at the end when completed add
waitHandle.Set();
waitHandle.WaitOne(); Waits for signal
waitHandle.Set(); signals completion.
For understanding concepts like signaling, see Thread Synchronization which would be a good place to start.
It's got examples too. You can then drill down into specific .net types based on what you're trying to do.. signal between threads within a process or across processes etc..

What is most CPU efficient method to make the worker threads wait for tasks?

In my current C#/NET 3.5 application, I have a task queue (thread safe) and I have 5 worker threads that has to constantly look for tasks in the queue. If a task is available, any one worker will dequeue the task and take required action.
My worker thread class is as follows:
public class WorkerThread
{
//ConcurrentQueue is my implementation of thread safe queue
//Essentially just a wrapper around Queue<T> with synchronization locks
readonly ConcurrentQueue<CheckPrimeTask> mQ;
readonly Thread mWorker;
bool mStop;
public WorkerThread (ConcurrentQueue<CheckPrimeTask> aQ) {
mQ = aQ;
mWorker = new Thread (Work) {IsBackground = true};
mStop = false;
}
private void Work () {
while (!mStop) {
if (mQ.Count == 0) {
Thread.Sleep (0);
continue;
}
var task = mQ.Dequeue ();
//Someone else might have been lucky in stealing
//the task by the time we dequeued it!!
if (task == null)
continue;
task.IsPrime = IsPrime (task.Number);
task.ExecutedBy = Thread.CurrentThread.ManagedThreadId;
//Ask the threadpool to execute the task callback to
//notify completion
ThreadPool.QueueUserWorkItem (task.CallBack, task);
}
}
private bool IsPrime (int number) {
int limit = Convert.ToInt32 (Math.Sqrt (number));
for (int i = 2; i <= limit; i++) {
if (number % i == 0)
return false;
}
return true;
}
public void Start () {
mStop = false;
mWorker.Start ();
}
public void Stop () {
mStop = true;
}
}
Problem is that when queue is empty, it consumes too much CPU (nearly 98%). I tried AutoResetEvent to notify the workers that queue has been changed. So they effectively wait for that signal to set. It has braught down the CPU to nearly 0% but I am not entirely sure whether this is the best method. Can you suggest a better method to keep the threads idle without hurting CPU usage?
Check out this implementation of a BlockingQueue. If the queue is empty, it uses Monitor.Wait() to put the thread to sleep. When an item is added, it uses Monitor.Pulse() to wake up a thread that is sleeping on the empty queue.
Another technique is to use a semaphore. Each time you add an item to a queue, call Release(). When you want an item from a queue, call WaitOne().
You currently have Thread.Sleep(0) in your Work method for where there are no queue items. Change it to anything greater than 0 and your CPU use will go down. Try 10 to start with...
You have a couple of options that I can think of.
One way is to place a small thread sleep during your loop. This will basically drop your CPU usage to 0 and is fairly standard way of doing this.
Another way is to use a reset (either auto or manual) as suggested by Mitch Wheat in the comments.
You could also devise some kind of IdleTask that has a thread sleep for a certain amount of time and if your queue is empty, just process the IdleTask (which will thread sleep).
If your Queue is thread safe then you would not need to do this...
//Someone else might have been lucky in stealing
//the task by the time we dequeued it!!
if (task == null)
continue;

What is the difference between ManualResetEvent and AutoResetEvent in .NET?

I have read the documentation on this and I think I understand. An AutoResetEvent resets when the code passes through event.WaitOne(), but a ManualResetEvent does not.
Is this correct?
Yes. It's like the difference between a tollbooth and a door. The ManualResetEvent is the door, which needs to be closed (reset) manually. The AutoResetEvent is a tollbooth, allowing one car to go by and automatically closing before the next one can get through.
Just imagine that the AutoResetEvent executes WaitOne() and Reset() as a single atomic operation.
The AutoResetEvent also guarantees to only release one waiting thread.
The short answer is yes. The most important difference is that an AutoResetEvent will only allow one single waiting thread to continue. A ManualResetEvent on the other hand will keep allowing threads, several at the same time even, to continue until you tell it to stop (Reset it).
Taken from C# 3.0 Nutshell book, by
Joseph Albahari
Threading in C# - Free E-Book
A ManualResetEvent is a variation on AutoResetEvent. It differs in that it doesn't automatically reset after a thread is let through on a WaitOne call, and so functions like a gate: calling Set opens the gate, allowing any number of threads that WaitOne at the gate through; calling Reset closes the gate, causing, potentially, a queue of waiters to accumulate until its next opened.
One could simulate this functionality with a boolean "gateOpen" field (declared with the volatile keyword) in combination with "spin-sleeping" – repeatedly checking the flag, and then sleeping for a short period of time.
ManualResetEvents are sometimes used to signal that a particular operation is complete, or that a thread's completed initialization and is ready to perform work.
I created simple examples to clarify understanding of ManualResetEvent vs AutoResetEvent.
AutoResetEvent: lets assume you have 3 workers thread. If any of those threads will call WaitOne() all other 2 threads will stop execution and wait for signal. I am assuming they are using WaitOne(). It is like; if I do not work, nobody works. In first example you can see that
autoReset.Set();
Thread.Sleep(1000);
autoReset.Set();
When you call Set() all threads will work and wait for signal. After 1 second I am sending second signal and they execute and wait (WaitOne()). Think about these guys are soccer team players and if one player says I will wait until manager calls me, and others will wait until manager tells them to continue (Set())
public class AutoResetEventSample
{
private AutoResetEvent autoReset = new AutoResetEvent(false);
public void RunAll()
{
new Thread(Worker1).Start();
new Thread(Worker2).Start();
new Thread(Worker3).Start();
autoReset.Set();
Thread.Sleep(1000);
autoReset.Set();
Console.WriteLine("Main thread reached to end.");
}
public void Worker1()
{
Console.WriteLine("Entered in worker 1");
for (int i = 0; i < 5; i++) {
Console.WriteLine("Worker1 is running {0}", i);
Thread.Sleep(2000);
autoReset.WaitOne();
}
}
public void Worker2()
{
Console.WriteLine("Entered in worker 2");
for (int i = 0; i < 5; i++) {
Console.WriteLine("Worker2 is running {0}", i);
Thread.Sleep(2000);
autoReset.WaitOne();
}
}
public void Worker3()
{
Console.WriteLine("Entered in worker 3");
for (int i = 0; i < 5; i++) {
Console.WriteLine("Worker3 is running {0}", i);
Thread.Sleep(2000);
autoReset.WaitOne();
}
}
}
In this example you can clearly see that when you first hit Set() it will let all threads go, then after 1 second it signals all threads to wait! As soon as you set them again regardless they are calling WaitOne() inside, they will keep running because you have to manually call Reset() to stop them all.
manualReset.Set();
Thread.Sleep(1000);
manualReset.Reset();
Console.WriteLine("Press to release all threads.");
Console.ReadLine();
manualReset.Set();
It is more about Referee/Players relationship there regardless of any of the player is injured and wait for playing others will continue to work. If Referee says wait (Reset()) then all players will wait until next signal.
public class ManualResetEventSample
{
private ManualResetEvent manualReset = new ManualResetEvent(false);
public void RunAll()
{
new Thread(Worker1).Start();
new Thread(Worker2).Start();
new Thread(Worker3).Start();
manualReset.Set();
Thread.Sleep(1000);
manualReset.Reset();
Console.WriteLine("Press to release all threads.");
Console.ReadLine();
manualReset.Set();
Console.WriteLine("Main thread reached to end.");
}
public void Worker1()
{
Console.WriteLine("Entered in worker 1");
for (int i = 0; i < 5; i++) {
Console.WriteLine("Worker1 is running {0}", i);
Thread.Sleep(2000);
manualReset.WaitOne();
}
}
public void Worker2()
{
Console.WriteLine("Entered in worker 2");
for (int i = 0; i < 5; i++) {
Console.WriteLine("Worker2 is running {0}", i);
Thread.Sleep(2000);
manualReset.WaitOne();
}
}
public void Worker3()
{
Console.WriteLine("Entered in worker 3");
for (int i = 0; i < 5; i++) {
Console.WriteLine("Worker3 is running {0}", i);
Thread.Sleep(2000);
manualReset.WaitOne();
}
}
}
autoResetEvent.WaitOne()
is similar to
try
{
manualResetEvent.WaitOne();
}
finally
{
manualResetEvent.Reset();
}
as an atomic operation
OK, normally it does not a good practice to add 2 answers in same thread, but I did not want to edit/delete my previous answer, since it can help on another manner.
Now, I created, much more comprehensive, and easy to understand, run-to-learn console app snippet below.
Just run the examples on two different consoles, and observe behaviour. You will get much more clear idea there what is happening behind the scenes.
Manual Reset Event
using System;
using System.Threading;
namespace ConsoleApplicationDotNetBasics.ThreadingExamples
{
public class ManualResetEventSample
{
private readonly ManualResetEvent _manualReset = new ManualResetEvent(false);
public void RunAll()
{
new Thread(Worker1).Start();
new Thread(Worker2).Start();
new Thread(Worker3).Start();
Console.WriteLine("All Threads Scheduled to RUN!. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("Main Thread is waiting for 15 seconds, observe 3 thread behaviour. All threads run once and stopped. Why? Because they call WaitOne() internally. They will wait until signals arrive, down below.");
Thread.Sleep(15000);
Console.WriteLine("1- Main will call ManualResetEvent.Set() in 5 seconds, watch out!");
Thread.Sleep(5000);
_manualReset.Set();
Thread.Sleep(2000);
Console.WriteLine("2- Main will call ManualResetEvent.Set() in 5 seconds, watch out!");
Thread.Sleep(5000);
_manualReset.Set();
Thread.Sleep(2000);
Console.WriteLine("3- Main will call ManualResetEvent.Set() in 5 seconds, watch out!");
Thread.Sleep(5000);
_manualReset.Set();
Thread.Sleep(2000);
Console.WriteLine("4- Main will call ManualResetEvent.Reset() in 5 seconds, watch out!");
Thread.Sleep(5000);
_manualReset.Reset();
Thread.Sleep(2000);
Console.WriteLine("It ran one more time. Why? Even Reset Sets the state of the event to nonsignaled (false), causing threads to block, this will initial the state, and threads will run again until they WaitOne().");
Thread.Sleep(10000);
Console.WriteLine();
Console.WriteLine("This will go so on. Everytime you call Set(), ManualResetEvent will let ALL threads to run. So if you want synchronization between them, consider using AutoReset event, or simply user TPL (Task Parallel Library).");
Thread.Sleep(5000);
Console.WriteLine("Main thread reached to end! ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
}
public void Worker1()
{
for (int i = 1; i <= 10; i++)
{
Console.WriteLine("Worker1 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(5000);
// this gets blocked until _autoReset gets signal
_manualReset.WaitOne();
}
Console.WriteLine("Worker1 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
}
public void Worker2()
{
for (int i = 1; i <= 10; i++)
{
Console.WriteLine("Worker2 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(5000);
// this gets blocked until _autoReset gets signal
_manualReset.WaitOne();
}
Console.WriteLine("Worker2 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
}
public void Worker3()
{
for (int i = 1; i <= 10; i++)
{
Console.WriteLine("Worker3 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(5000);
// this gets blocked until _autoReset gets signal
_manualReset.WaitOne();
}
Console.WriteLine("Worker3 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
}
}
}
Auto Reset Event
using System;
using System.Threading;
namespace ConsoleApplicationDotNetBasics.ThreadingExamples
{
public class AutoResetEventSample
{
private readonly AutoResetEvent _autoReset = new AutoResetEvent(false);
public void RunAll()
{
new Thread(Worker1).Start();
new Thread(Worker2).Start();
new Thread(Worker3).Start();
Console.WriteLine("All Threads Scheduled to RUN!. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("Main Thread is waiting for 15 seconds, observe 3 thread behaviour. All threads run once and stopped. Why? Because they call WaitOne() internally. They will wait until signals arrive, down below.");
Thread.Sleep(15000);
Console.WriteLine("1- Main will call AutoResetEvent.Set() in 5 seconds, watch out!");
Thread.Sleep(5000);
_autoReset.Set();
Thread.Sleep(2000);
Console.WriteLine("2- Main will call AutoResetEvent.Set() in 5 seconds, watch out!");
Thread.Sleep(5000);
_autoReset.Set();
Thread.Sleep(2000);
Console.WriteLine("3- Main will call AutoResetEvent.Set() in 5 seconds, watch out!");
Thread.Sleep(5000);
_autoReset.Set();
Thread.Sleep(2000);
Console.WriteLine("4- Main will call AutoResetEvent.Reset() in 5 seconds, watch out!");
Thread.Sleep(5000);
_autoReset.Reset();
Thread.Sleep(2000);
Console.WriteLine("Nothing happened. Why? Becasuse Reset Sets the state of the event to nonsignaled, causing threads to block. Since they are already blocked, it will not affect anything.");
Thread.Sleep(10000);
Console.WriteLine("This will go so on. Everytime you call Set(), AutoResetEvent will let another thread to run. It will make it automatically, so you do not need to worry about thread running order, unless you want it manually!");
Thread.Sleep(5000);
Console.WriteLine("Main thread reached to end! ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
}
public void Worker1()
{
for (int i = 1; i <= 5; i++)
{
Console.WriteLine("Worker1 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(500);
// this gets blocked until _autoReset gets signal
_autoReset.WaitOne();
}
Console.WriteLine("Worker1 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
}
public void Worker2()
{
for (int i = 1; i <= 5; i++)
{
Console.WriteLine("Worker2 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(500);
// this gets blocked until _autoReset gets signal
_autoReset.WaitOne();
}
Console.WriteLine("Worker2 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
}
public void Worker3()
{
for (int i = 1; i <= 5; i++)
{
Console.WriteLine("Worker3 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(500);
// this gets blocked until _autoReset gets signal
_autoReset.WaitOne();
}
Console.WriteLine("Worker3 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
}
}
}
AutoResetEvent maintains a boolean variable in memory. If the boolean variable is false then it blocks the thread and if the boolean variable is true it unblocks the thread.
When we instantiate an AutoResetEvent object, we pass the default value of boolean value in the constructor. Below is the syntax of instantiate an AutoResetEvent object.
AutoResetEvent autoResetEvent = new AutoResetEvent(false);
WaitOne method
This method blocks the current thread and wait for the signal by other thread. WaitOne method puts the current thread into a Sleep thread state. WaitOne method returns true if it receives the signal else returns false.
autoResetEvent.WaitOne();
Second overload of WaitOne method wait for the specified number of seconds. If it does not get any signal thread continues its work.
static void ThreadMethod()
{
while(!autoResetEvent.WaitOne(TimeSpan.FromSeconds(2)))
{
Console.WriteLine("Continue");
Thread.Sleep(TimeSpan.FromSeconds(1));
}
Console.WriteLine("Thread got signal");
}
We called WaitOne method by passing the 2 seconds as arguments. In the while loop, it wait for the signal for 2 seconds then it continues its work. When the thread got the signal WaitOne returns true and exits the loop and print the "Thread got signal".
Set method
AutoResetEvent Set method sent the signal to the waiting thread to proceed its work. Below is the syntax of calling Set method.
autoResetEvent.Set();
ManualResetEvent maintains a boolean variable in memory. When the boolean variable is false then it blocks all threads and when the boolean variable is true it unblocks all threads.
When we instantiate a ManualResetEvent, we initialize it with default boolean value.
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
In the above code, we initialize the ManualResetEvent with false value, that means all the threads which calls the WaitOne method will block until some thread calls the Set() method.
If we initialize ManualResetEvent with true value, all the threads which calls the WaitOne method will not block and free to proceed further.
WaitOne Method
This method blocks the current thread and wait for the signal by other thread. It returns true if its receives a signal else returns false.
Below is the syntax of calling WaitOne method.
manualResetEvent.WaitOne();
In the second overload of WaitOne method, we can specify the time interval till the current thread wait for the signal. If within time internal, it does not receives a signal it returns false and goes into the next line of method.
Below is the syntax of calling WaitOne method with time interval.
bool isSignalled = manualResetEvent.WaitOne(TimeSpan.FromSeconds(5));
We have specify 5 seconds into the WaitOne method. If the manualResetEvent object does not receives a signal between 5 seconds, it set the isSignalled variable to false.
Set Method
This method is used for sending the signal to all waiting threads. Set() Method set the ManualResetEvent object boolean variable to true. All the waiting threads are unblocked and proceed further.
Below is the syntax of calling Set() method.
manualResetEvent.Set();
Reset Method
Once we call the Set() method on the ManualResetEvent object, its boolean remains true. To reset the value we can use Reset() method. Reset method change the boolean value to false.
Below is the syntax of calling Reset method.
manualResetEvent.Reset();
We must immediately call Reset method after calling Set method if we want to send signal to threads multiple times.
Yes. This is absolutely correct.
You could see ManualResetEvent as a way to indicate state. Something is on (Set) or off (Reset). An occurrence with some duration. Any thread waiting for that state to happen can proceed.
An AutoResetEvent is more comparable to a signal. A one shot indication that something has happened. An occurrence without any duration. Typically but not necessarily the "something" that has happened is small and needs to be handled by a single thread - hence the automatic reset after a single thread have consumed the event.
Yes, thats right.
You can get an idea by the usage of these two.
If you need to tell that you are finished with some work and other (threads) waiting for this can now proceed, you should use ManualResetEvent.
If you need to have mutual exclusive access to any resource, you should use AutoResetEvent.
If you want to understand AutoResetEvent and ManualResetEvent you need to understand not threading but interrupts!
.NET wants to conjure up low-level programming the most distant possible.
An interrupts is something used in low-level programming which equals to a signal that from low became high (or viceversa). When this happens the program interrupt its normal execution and move the execution pointer to the function that handles this event.
The first thing to do when an interrupt happend is to reset its state, becosa the hardware works in this way:
a pin is connected to a signal and the hardware listen for it to change (the signal could have only two states).
if the signal changes means that something happened and the hardware put a memory variable to the state happened (and it remain like this even if the signal change again).
the program notice that variable change states and move the execution to a handling function.
here the first thing to do, to be able to listen again this interrupt, is to reset this memory variable to the state not-happened.
This is the difference between ManualResetEvent and AutoResetEvent.
If a ManualResetEvent happen and I do not reset it, the next time it happens I will not be able to listen it.

Categories

Resources