Fundamental difference between Join() Lock() - c#

For the case of both Join() and lock() one thread can execute after the other.What is the main difference?

Lock is a monitor which is used to guarantee that only 1 thread can execute at a time.
lock(myobj)
{
// only 1 thread here
}
Join is used to wait for a thread to complete, before execution continues.
anotherThread.Join();
// execution here only when anotherThread is complete

Thread.Join() waits for a thread to exit. Monitor.Enter(obj) (how the compiler expresses the entry to a lock statement) waits for no other thread to hold obj's object lock.
The former is used to help manage thread lifetimes, the latter to control concurrency.

In the below code, the second thread waits for the first thread to exit. So, the first thread starts and gets completed before second thread starting.
public void threadExample1()
{
Thread t1=new Thread(fun1);
Thread t2=new Thread(fun2);
t1.Start();
t1.Join();
t2.Start();
}
In the second example, we don't know which thread will start first, but we know there is only one thread will run at a time because of lock
public readonly object locker = new object();
public void threadExample2()
{
Thread t1=new Thread(fun1);
Thread t2=new Thread(fun2);
t1.Start();
t2.Start();
}
public void fun1()
{
lock(locker)
{
for (int i = 0; i < 10; i++)
Console.Write("1");
}
}
public void fun2()
{
lock(locker)
{
for (int i = 0; i < 10; i++)
Console.Write("2");
}
}
the output will be either "11111111112222222222" or "22222222221111111111" for lock example while only "11111111112222222222" for Join example

Related

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

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);
}
}
}
}

Task.WaitAll() not working as expected

I'm trying to figure out how to work with the Task class. In the past I have always used the regular Thread class, but I'm trying to grasp all of the asynchronous programming...
As an example, I created a main Winforms application that has all the code.
The relevant code for my problem is:
//Relevant delegates
public delegate void MethodAction(int num);
public delegate void MethodConversion();
public delegate void OnCompletionAction(string completiontext);
//Button user presses
private void button4_Click(object sender, EventArgs e)
{
richTextBox1.Clear();
sw.Reset();
sw.Start();
Sync.RunAsync3(calcSim);
}
//The method that simulates a calculation by adding a sleep
//the input param threadlength is just to allow threads to take longer than others
//since I'm multithreading, I have to invoke the writing code on the windows RichTextbox control
private void calcSim(int threadlength)
{
string threadname = Thread.CurrentThread.Name;
for (int i = 0; i < 10; i++) //Thread calc should take 3s
{
Thread.Sleep(300 + threadlength);
richTextBox1.Invoke((MethodConversion)(() =>
{
richTextBox1.AppendText(string.Format("Thread: {0}\tVersion: {1}\n", threadname, (i + 1).ToString()));
}));
}
}
//Class that contains the different processing methods
public static class Sync
{
public static event OnCompletionAction OnProcCompletion;
public static void RunAsync3(MethodAction doM)
{
Task[] t = new Task[4];
for(int i = 0; i < 4; i++)
{
t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
}
Task.WaitAll(t);
if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
}
}
The problem lies within Task.WaitAll(t)... For some reason, which I can't figure out, it completely blocks on that line and doesn't respond anymore. If I omit that line, the form gets updated in realtime and the execution take about 3 seconds.
My question is: why isn't Task.WaitAll() blocking the UI thread for 3 seconds before releasing it and allowing the rest of the code to execute?
I know it should be blocking the UI for some time (until all threads are calculated), but it blocks the complete app endlessly. It seems to be waiting forever?
EDIT
I've been suggested to use WhenAll instead of WaitAll. I have rewritten RunAsync3 as follows:
public static void RunAsync3(MethodAction doM)
{
Task[] t = new Task[4];
for(int i = 0; i < 4; i++)
{
t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
}
//Task.WaitAll(t); -> deadlock
Task.WaitAll(new Task [] { Task.WhenAll(t) });
if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
}
But this is still getting deadlocked...? I might be using the WhenAll incorrectly?
EDIT 2
Because everybody claiming that I was blocking the UI thread were right, I decided to try this another way: by running a new thread as my calling thread inside the UI thread (so that blocking now would occur on my thread instead of UI thread). This works, but is obviously not the best way to do this!
private void button4_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(() =>
{
richTextBox1.Invoke((MethodConversion)(() => richTextBox1.Clear()));
sw.Reset();
sw.Start();
Sync.RunAsync3(calcSim);
}));
t.Start();
}
public static void RunAsync3(MethodAction doM)
{
Task[] t = new Task[4];
for(int i = 0; i < 4; i++)
{
t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
}
Task.WaitAll(t);
//Task.WaitAll(new Task [] { Task.WhenAll(t) });
if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
}
You're causing a deadlock.
The UI thread is waiting for 4 tasks to be completed.
On the other hand, those 4 tasks, running calcSim are trying to invoke code on the UI thread -> Deadlock.
You should be using Task.WhenAll() instead. That method will return a new task that will be marked as completed when all your for tasks have completed. If you await that task, your UI thread will be freed, and so calcSim will be able to invoke code on the UI thread, avoiding a deadlock.
Update
You're using it wrong. You're still using WaitAll, which is a blocking call. You should replace it with WhenAll.
await Task.WhenAll(t);
From the documentation:
Creates a task that will complete when all of the supplied tasks have
completed.
By calling await on the result, your UI thread will be free - until all 4 tasks complete. When that happens, your RunAsync3 method will resume.
Task.WaitAll blocks and waits for all task to complete and you are calling it on the UI thread.
All your task are trying to call richTextBox1.Invoke (in the UI thread) but your UI thread is blocked in Task.WaitAll. Deadlock.
Because it waits as your threads finish. They run exactly 3 seconds 300X10

Thread execution order

I have the following C# code:
using System;
using System.Threading;
// Simple threading scenario: Start a static method running
// on a second thread.
public class ThreadExample {
// The ThreadProc method is called when the thread starts.
// It loops ten times, writing to the console and yielding
// the rest of its time slice each time, and then ends.
public static void ThreadProc() {
for (int i = 0; i < 10; i++) {
Console.WriteLine("ThreadProc: {0}", i);
// Yield the rest of the time slice.
Thread.Sleep(0);
}
}
public static void Main() {
Console.WriteLine("Main thread: Start a second thread.");
// The constructor for the Thread class requires a ThreadStart
// delegate that represents the method to be executed on the
// thread. C# simplifies the creation of this delegate.
Thread t = new Thread(new ThreadStart(ThreadProc));
// Start ThreadProc. Note that on a uniprocessor, the new
// thread does not get any processor time until the main thread
// is preempted or yields. Uncomment the Thread.Sleep that
// follows t.Start() to see the difference.
t.Start();
//Thread.Sleep(0);
for (int i = 0; i < 4; i++) {
Console.WriteLine("Main thread: Do some work.");
Thread.Sleep(0);
}
Console.WriteLine("Main thread: Call Join(), to wait until ThreadProc ends.");
t.Join();
Console.WriteLine("Main thread: ThreadProc.Join has returned. Press Enter to end program.");
Console.ReadLine();
}
}
It's a long time since I studied the thread to university, the only thing that I still remember is:
thread execution is pretty unpredictable and may vary based underlayng
OS.
So the real question is: why I can't be sure not even about the first execution of ThreadProc? What happen when I execute t.Start()? Why ThreadProc: 0 isn't printed immediately after Main thread: Start a second thread in every execution?
Why I can't be sure not even about the first execution of ThreadProc?
Because this is nondeterministic neither by .NET nor Windows OS documentation (I suppose you are using Windows)
What happen when I execute t.Start()?
Thread will be scheduled by OS for execution. MSDN: "Causes a thread to be scheduled for execution."
Why ThreadProc: 0 isn't printed immediately after Main thread: Start a
second thread in every execution?
Because there is some delay between Thread.Start() call and actual thread start

How to Cancel a Thread?

In case of BackgroundWorker, a cancel can be reported by the e.Cancel - property of the DoWork - event handler.
How can I achieve the same thing with a Thread object?
Here is a full example of one way of doing it.
private static bool _runThread;
private static object _runThreadLock = new object();
private static void Main(string[] args)
{
_runThread = true;
Thread t = new Thread(() =>
{
Console.WriteLine("Starting thread...");
bool _localRunThread = true;
while (_localRunThread)
{
Console.WriteLine("Working...");
Thread.Sleep(1000);
lock (_runThreadLock)
{
_localRunThread = _runThread;
}
}
Console.WriteLine("Exiting thread...");
});
t.Start();
// wait for any key press, and then exit the app
Console.ReadKey();
// tell the thread to stop
lock (_runThreadLock)
{
_runThread = false;
}
// wait for the thread to finish
t.Join();
Console.WriteLine("All done.");
}
In short; the thread checks a bool flag, and keeps runing as long as the flag is true. I prefer this approach over calling Thread.Abort becuase it seems a bit nicer and cleaner.
Generally you do it by the thread's execute being a delegate to a method on an object, with that object exposing a Cancel property, and the long-running operation periodically chercking that property for tru to determine whether to exit.
for example
public class MyLongTunningTask
{
public MyLongRunninTask() {}
public volatile bool Cancel {get; set; }
public void ExecuteLongRunningTask()
{
while(!this.Cancel)
{
// Do something long running.
// you may still like to check Cancel periodically and exit gracefully if its true
}
}
}
Then elsewhere:
var longRunning = new MyLongTunningTask();
Thread myThread = new Thread(new ThreadStart(longRunning.ExecuteLongRunningTask));
myThread.Start();
// somewhere else
longRunning.Cancel = true;
A blocked thread can be stopped prematurely in one of two ways:
Thread.Interrupt
Thread.Abort
The main question is if the thread works on any ressources which need to be released correctly - in this case - you need to work with a property on the actual object which runs the thread.
There's Thread.Abort, which works by injecting a ThreadAbortException into the thread. It's a little risky because:
Your thread can get stuck if it's executing native code at the time
The code in the thread better be exception-safe, because this ThreadAbortException could happen on any line of code within it, even something innocent like i = i + 1
You're better off coding your own signalling mechanism between your GUI thread and the background thread. It's hard to recommend something without knowing what's going on inside that thread, but where I have a thread that works by waiting on some object in a loop, I use an AutoResetEvent and wait on that too.

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