Hi guys I start threads with such code:
Thread[] thr;
private void button1_Click(object sender, EventArgs e)
{
decimal value = numericUpDown2.Value;
int i = 0;
threads_count = (int)(value);
thr = new Thread[threads_count];
for (; i < threads_count; i++)
{
thr[i] = new Thread(new ThreadStart(go));
thr[i].IsBackground = true;
thr[i].Start();
}
}
How to stop all them if my condition become true
A number of the answers say to abort the thread. Never abort a thread unless it is an emergency situation and you are shutting down the application.
The CLR guarantees that its internal data structures are not corrupted by a thread abort. This is the only (*) guarantee made by the CLR with respect to thread aborts. It specifically does not guarantee:
That the thread actually will abort. Threads can harden themselves against being terminated.
That any data structure that is not in the CLR itself will be uncorrupted. Thread aborts in the middle of crucial operations can leave BCL data structures or user data structures in arbitrarily inconsistent states. This can crash your process mysteriously later.
That locks will be released. Aborting threads can cause locks to be held forever, it can cause deadlocks, and so on.
In case I am not being clear: it is insanely dangerous to abort a thread and you should only do so when all the alternatives are worse.
So what if you want to start up a thread and then shut it down cleanly?
First, don't do that. Don't start a thread in the first place. Start a Task<T> with a cancellation token and when you want to shut it down, signal its cancellation token.
If you do have to start a thread, then start the thread such that there is some mechanism whereby the main thread and the working thread can cleanly and safely communicate "I want you to shut yourself down cleanly at this time".
If you don't know how to do that then stop writing multithreaded code until you learn how to do that.
(*) This is a small lie; the CLR also makes certain guarantees with respect to the interactions of thread aborts and special code regions such as constrained execution regions and finally blocks.
You can use a CancellationToken to signal when the operation should stop.
Create a CancellationTokenSource as an instance field of your type that you initialize in the button click handler.
In your background method periodically check the IsCancellationRequested property of the Token in the token source, or call ThrowIfCancellationRequested() if you want it to just throw an exception if it is canceled.
When you want to stop the threads call Cancel on the token source.
Brutal way (not recommended) - use Thread.Abort method to abort threads. This method raises ThreadAbortException on thread. Like this:
foreach(Thread thread in thr)
thread.Abort();
But better way is notifying thread about cancellation and letting it correctly finish its job. You can do it simply with .Net 4 tasks:
Task[] thr = new Task[threads_count];
var source = new CancellationTokenSource();
for (int i = 0; i < threads_count; i++)
{
thr[i] = Task.Factory.StartNew(go, source.Token);
}
// later, when condition is met
source.Cancel();
And here is how cancellation should look like:
private static void go(object obj)
{
CancellationToken token = (CancellationToken)obj;
while (true)
{
if (token.IsCancellationRequested)
return;
// do some work
}
}
If you want to know how to terminate the thread gracefully, I'd recommend you to take a look the following example on MSDN:
using System;
using System.Threading;
public class Worker
{
public void DoWork()
{
while (!_shouldStop)
{
Console.WriteLine("worker thread: working...");
}
Console.WriteLine("worker thread: terminating gracefully.");
}
public void RequestStop()
{
_shouldStop = true;
}
// Volatile is used as hint to the compiler that this data
// member will be accessed by multiple threads.
private volatile bool _shouldStop;
}
public class WorkerThreadExample
{
static void Main()
{
Worker workerObject = new Worker();
Thread workerThread = new Thread(workerObject.DoWork);
workerThread.Start();
Console.WriteLine("main thread: Starting worker thread...");
while (!workerThread.IsAlive); // Loop until worker thread activates
// Put the main thread to sleep for 1 millisecond to
// allow the worker thread to do some work:
Thread.Sleep(1);
workerObject.RequestStop();
// Use the Join method to block the current thread
// until the object's thread terminates.
workerThread.Join();
Console.WriteLine("main thread: Worker thread has terminated.");
}
}
This is Windows Form Code in which:
1) On Clicking start button, Main Thread creates another Thread
2) Again created Thread creates on more Thread.
3) On clicking Stop button, First the last Thread should terminate Then the Thread created by Main thread should Terminate.
namespace Thread_TerminateProblem
{
public partial class Form1 : Form
{
private static AutoResetEvent m_ResetEvent = null;
private static ManualResetEvent m_ResetEvent_Thread = new ManualResetEvent(false);
enum ServiceState { Start, Stop };
bool flag = false;
int x = 0;
ServiceState _state;
public Form1()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
flag = true;
_state = ServiceState.Start;
m_ResetEvent = new AutoResetEvent(true);
Thread t1 = new Thread(fun_Thread1);
t1.Start();
t1.Name = "Thread1";
}
private void btnStop_Click(object sender, EventArgs e)
{
_state = ServiceState.Stop;
m_ResetEvent.Set();
}
private void fun_Thread1()
{
while (true)
{
m_ResetEvent.WaitOne();
switch (_state)
{
case ServiceState.Start:
{
Thread t = new Thread(fun_Thread2);
t.Start();
t.Name = "Thread2";
break;
}
case ServiceState.Stop:
{
m_ResetEvent_Thread.Set();
flag = true;
break;
}
}
// When the child Thread terminates, Then only this thread should terminate
if (flag == true)
{
// Waiting for notification from child Thread
notifyParent.WaitOne();
Thread.Sleep(100);
break;
}
m_ResetEvent.Reset();
}
}
private static ManualResetEvent notifyParent = new ManualResetEvent(false);
private void fun_Thread2()
{
while (true)
{
if (m_ResetEvent_Thread.WaitOne(1, false))
{
notifyParent.Set();
break;
}
x++;
}
}
}
}
simplistic answer is to use the thread Abort() method however your code does not really make it clear what condition,
what loop tests vs a condition? why do you need to abort a thread? I am asking as there may be a better way to approach this
Related
Task description:
Write a program that reads an positive integer value n (n > 3), then
creates n threads (each thread has id; id starts from 1) and works
until it receives a stop signal. All of n threads are waiting for a
signal. Every second main thread sends a signal for a random thread,
then that thread should print its id and return to a waiting state.
Requirements:
All additional threads should be finished correctly. At the thread
function exit, a message about exit should be printed. While the
thread is waiting for the condition variable, spurious wakeup should
be checked. Only std::cout allowed for text output. Stop signal is
SIGINT (ctrl+c).
I have written the following code for the above question but in output, all the threads are not exiting. I am not able to figure out the problem as I am new to this topic. Any kind of help will be really appreciated.
class Program
{
public static void Main()
{
var numberofthreads = Convert.ToInt32(Console.ReadLine());
ProcessingClass myobject = new ProcessingClass();
myobject.createThreads(numberofthreads);
}
}
public class ProcessingClass
{
public Mutex mymutex = new Mutex();
private bool thread_flag = false;
public void createThreads(int numberofthreads)
{
var threads = new List<Thread>(numberofthreads);
for (int i = 0; i < numberofthreads; i++)
{
Thread th = new Thread(() =>
{
threadsworking();
});
th.Name = "Thread" + i;
th.Start(); // <-- .Start() makes the thread start running
threads.Add(th);
}
Console.CancelKeyPress += (object sender, ConsoleCancelEventArgs e) =>
{
var isCtrlC = e.SpecialKey == ConsoleSpecialKey.ControlC;
if (isCtrlC)
{
thread_flag = true;
int num = 1;
foreach (var thread in threads)
{
thread.Join();
Console.WriteLine($"Thread {num} exits");
num++;
}
}
e.Cancel = true;
};
}
public void threadsworking()
{
while (thread_flag == false)
{
mymutex.WaitOne(); // Wait until it is safe to enter.
Console.WriteLine("{0}", Thread.CurrentThread.Name);
Thread.Sleep(1000); // Wait until it is safe to enter.
mymutex.ReleaseMutex(); // Release the Mutex.
}
}
}
enter image description here
Consider preventing mutex from blocking threads from exiting.
When you use mutex.WaitOne() it blocks execution until the Mutex is owned by that thread. This can be really helpful for ensuring a thread has exclusive control over a shared resource. However, where this becomes a problem is when you want to arbitrarily end those threads such as when you invoke the event on the Console.CancelKeyPress.
You can see the effects of this by logging before and after the thread.Join() call you do in the event.
thread_flag = true;
int num = 1;
foreach (var thread in threads)
{
Console.WriteLine($"Joining {thread.Name}");
thread.Join();
Console.WriteLine($"Joined {thread.Name}");
Console.WriteLine($"Thread {num} exits");
num++;
}
When we do that logging it will show us that when you call Join() on Thread # 1 you see Joining 1. Then there is a really long pause, other threads still are doing work, and then finally all the threads join back to back.
The reason for this is - while Join() is waiting for Thread 1 to finish, Thread 1 is still waiting for the mutex.
Even though you set the thread_flag flag to true, Thread 1 can't exit because it hasn't taken ownership of the mutex to perform it's work and eventually exit the while() loop.
We can solve this issue fairly simply.
Consider using a timeout when waiting for the mutex
When you call .WaitOne(n) on the mutex you can wait for n given milliseconds and give up taking ownership of the mutex.
This will allow more frequent evaluations of the while loop, and subsequently more times that the threadsworking method checks to see if it should exit(using the thread_flag flag).
Heres a short example how implementing that change might look
public void threadsworking()
{
while (thread_flag == false)
{
// wait to enter the mutex, give timeout to prevent blocking
// until mutex opens and use the bool returned to determine
// if we should release the mutex or not
if (mymutex.WaitOne(1))
{
try
{
Console.WriteLine("{0}", Thread.CurrentThread.Name);
Thread.Sleep(1000); // Wait until it is safe to enter.
}
finally
{
// make sure even if we encounter an error the mutex is released
mymutex.ReleaseMutex(); // Release the Mutex.
}
}
// allow other threads to continue their work instead of blocking with a while loop, this is optional depending on the workload
Thread.Yield();
}
}
I have the following code and the thread is not stoping even if i close the form or exit the program with System.Windows.Forms.Application.Exit();.
My code:
bool shouldStop = false;
private void button1_Click(object sender, EventArgs e)
{
backgroundThread = new Thread(
new ThreadStart(() =>
{
for (int j = 0; j <= 1000; j++)
{
if (!shouldStop)
{
//do something
}
else
{
break;
}
}
}));
backgroundThread.Start();
}
private void FormUpdateDB_FormClosing(object sender, FormClosingEventArgs e)
{
shouldStop = true;
}
So first off, exiting from the application simply ends that thread's message loop. That won't directly tear down any other threads.
If you want the exiting of this application to end this other thread then all you need to do is make it a background thread. (Set the IsBackground property to true.) and the thread will be torn down when no other non-background threads are running.
As for why the thread keeps going after you set shouldStop to true, you are not properly synchronizing access to the variable. Because there is no memory barrier in place, the other thread is free to continue reading from a cached value of that variable, for as long as it wants to. While you could synchronize access yourself, you shouldn't try to. Instead, if it's important that this thread be a non-background thread (because it's doing something that cannot be stopped at some arbitrary point in time) then you should use a CancellationToken to cooperatively cancel another task. The implementation of that type properly synchronizes access to the data between threads.
Try adding
backgroundThread.IsBackground = true;
before the call to Start()
I have a simple program here below that has 2 threads performing some task.
Thread1 is the data feeder. Thread2 is the data processor.
So far the work being done through my approach is working but I want to have better way of getting notified when the work completes
Here is the code
class Program
{
private static BlockingCollection<int> _samples = new BlockingCollection<int>();
private static CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private static bool _cancel;
static void Main(string[] args)
{
ThreadStart thread1 = delegate
{
ProcessThread1();
};
new Thread(thread1).Start();
ThreadStart thread2 = delegate
{
ProcessThread2();
};
new Thread(thread2).Start();
Console.WriteLine("Press any key to cancel..");
Console.Read();
_cancel = true;
_cancellationTokenSource.Cancel();
Console.Read();
}
private static void ProcessThread1()
{
for (int i = 0; i < 10; i++)
{
if (_cancel)
{
break;
}
Console.WriteLine("Adding data..");
_samples.TryAdd(i,100);
Thread.Sleep(1000);
}
// I dont like this. Instead can I get notified in the UI thread that this thread is complete.
_cancel = true;
_cancellationTokenSource.Cancel();
}
private static void ProcessThread2()
{
while (!_cancellationTokenSource.IsCancellationRequested)
{
int data;
if (_samples.TryTake(out data, 100))
{
// Do some work.
Console.WriteLine("Processing data..");
}
}
Console.WriteLine("Cancelled.");
}
}
I want the program to exit if the cancel is requested by the user or when the work completes.
I am not sure how I can get notified when the ProcessThread1 runs out of work. Currently I am setting cancel = true when the work is complete but it seem not right. Any help appreciated.
If you use Task instead of manually creating threads, you can attach a continuation on your task to notify your UI that the work is complete.
Task workOne = Task.Factory.StartNew( () => ProcessThread1());
workOne.ContinueWith(t =>
{
// Update UI here
}, TaskScheduler.FromCurrentSynchronizationContext());
With .NET 4.5, this becomes even easier, as you can potentially use the new async language support:
var workOne = Task.Run(ProcessThread1);
var workTwo = Task.Run(ProcessThread2);
// asynchronously wait for both tasks to complete...
await Task.WhenAll(workOne, workTwo);
// Update UI here.
Note that these both are designed with a user interface in mind - and will behave unusually in a console application, as there is no current synchronization context in a console application. When you move this to a true user interface, it will behave correctly.
Start one more thread whose only job is to wait on console input:
private void ConsoleInputProc()
{
Console.Write("Press Enter to cancel:");
Console.ReadLine();
_cancellationTokenSource.Cancel();
}
Your main thread then starts the two processing threads and the input thread.
// create and start the processing threads
Thread t1 = new Thread(thread1);
Thread t2 = new Thread(thread2);
t1.Start();
t2.Start();
// create and start the input thread
Thread inputThread = new Thread(ConsoleInputProc);
inputThread.Start();
Then, you wait on the two processing threads:
t1.Join();
// first thread finished. Request cancellation.
_cancellationTokenSource.Cancel();
t2.Join();
So if the user presses Enter, then the input thread sets the cancellation flags. thread1 and thread2 both see the cancellation request and exit.
If thread1 completes its work, then the main thread sets the cancellation flag and thread2 will cancel.
In either case, the program won't exit until thread 2 exits.
There's no need to kill the input thread explicitly. It will die when the program exits.
By the way, I would remove these lines from the thread 1 proc:
// I dont like this. Instead can I get notified in the UI thread that this thread is complete.
_cancel = true;
_cancellationTokenSource.Cancel();
I would remove the _cancel variable altogether, and have the first thread check IsCancellationRequested just like the second thread does.
It's unfortunate that you have to start a dedicated thread to wait on console input, but it's the only way I know of to accomplish this. The Windows console doesn't appear to have a waitable event.
Note that you could do this same thing with Task, which overall is easier to use. The code that the tasks perform would be the same.
Update
Looking at the bigger picture, I see that you have a typical producer/consumer setup with BlockingCollection. You can make your producer and consumer threads a lot cleaner:
private static void ProcessThread1()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Adding data..");
_samples.TryAdd(i, Timeout.Infinite, _cancellationTokenSource.Token);
// not sure why the sleep is here
Thread.Sleep(1000);
}
// Marks the queue as complete for adding.
// When the queue goes empty, the consumer will know that
// no more data is forthcoming.
_samples.CompleteAdding();
}
private static void ProcessThread2()
{
int data;
while (_samples.TryTake(out data, TimeSpan.Infinite, _cancellationTokenSource.Token))
{
// Do some work.
Console.WriteLine("Processing data..");
}
Console.WriteLine("Cancelled.");
}
You'll still need that input thread (unless you want to spin a loop on Console.KeyAvailable), but this greatly simplifies your producer and consumer.
In this code, when button1 is clicked twice, it creates 2 separate threads. On one click, it creates a new thread on the heap and field t1 points to the new thread on the heap. When I click button2, it aborts the last thread (which t1 refers to).
How do I abort the other thread?
Thread t1;
ThreadStart ts1;
private void button1_Click(object sender, EventArgs e)
{
ts1 = new ThreadStart(myfunc);
t1 = new Thread(ts1);
t1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
t1.Abort();
}
Well, the OO answer would be to hold a list of threads as a field.
private readonly List<Thread> threads = new List<Thread>();
And to then add the newly constructed thread to the list in the first handler.
var thread = new Thread(myfunc);
thread.Start();
threads.Add(thread);
Then you could iterate through each thread in the second handler, aborting each of them in turn.
foreach(var thread in threads)
thread.Abort();
But I think the most important point here is that there is almost never a good reason to call Thread.Abort.
From the MSDN page:
When a thread calls Abort on itself,
the effect is similar to throwing an
exception; the ThreadAbortException
happens immediately, and the result is
predictable. However, if one thread
calls Abort on another thread, the
abort interrupts whatever code is
running. There is also a chance that a
static constructor could be aborted.
In rare cases, this might prevent
instances of that class from being
created in that application domain. In
the .NET Framework versions 1.0 and
1.1, there is a chance the thread could abort while a finally block is
running, in which case the finally
block is aborted.
The thread that calls Abort might
block if the thread that is being
aborted is in a protected region of
code, such as a catch block, finally
block, or constrained execution
region. If the thread that calls Abort
holds a lock that the aborted thread
requires, a deadlock can occur.
You would be much better off using some form of signalling, such as setting a ManualResetEvent that each thread will poll at perioidic intervals. Alternatively, you could use the BackgroundWorker class that has some support for task-cancellation (call CancelAsync on it, and get the worker threads to test CancellationPending periodically). If you are on .NET 4.0, you can also use the TPL.
I would recommend you to take a look at the built in synchronization primitives such as ManualResetEvent and WaitHandle. You can ask a thread if it's running or not by trying to join the thread with Thread.Join. Aborting a thread should only be done as a last resort if the thread is unresponsive.
Here is an modified example of your code that shows how you can prevent the thread from be restarted before it's been stopped properly.
public partial class MainForm : Form
{
private Thread t1;
private ThreadStart ts1;
private ManualResetEvent t1resetEvent;
public MainForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Got a thread?
if (t1 != null) {
if (!t1.Join(0)) {
// The thread seems to be running.
// You have to stop the thread first.
return;
}
}
t1resetEvent = new ManualResetEvent(false);
ts1 = new ThreadStart(MyFunc);
t1 = new Thread(ts1);
t1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
// Got a thread?
if (t1 != null)
{
// Set the reset event so the thread
// knows it's time to stop.
t1resetEvent.Set();
// Give the thread four seconds to stop.
if (!t1.Join(4000)) {
// It did not stop, so abort it.
t1.Abort();
}
}
}
private void MyFunc()
{
// Long running operation...
while (true)
{
// Do someone want us to exit?
if (t1resetEvent.WaitOne(0)) {
return;
}
}
}
}
The others have given the long versions of the answer, however the obvious simple solution is to simply skip recreating the thread object:
public partial class Form1 : Form
{
Thread thread1;
ThreadStart threadStart1;
public Form1()
{
InitializeComponent();
threadStart1 = new ThreadStart(threadTarget);
thread1 = new Thread(threadStart1);
thread1.Name = "Button1 thread";
}
private void button1_Click(object sender, EventArgs e)
{
thread1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
thread1.Abort();
}
private void threadTarget()
{
Console.WriteLine(Thread.CurrentThread.Name);
for (int i = 0; i < 100; i++)
{
Console.WriteLine(i);
Thread.Sleep(500);
}
}
}
However, I would consider reading up on Threading in .NET using one these guides (I'd recommend Joseph Albahari's guide on aborting - the author of C# in a nutshell) rather than use this method, particularly if you're performing IO or database operations which can leave the objects in unexpected states.
Also, have in mind that calling Abort on a Thread is evil. You should stop the thread with a boolean condition or something like that.
Check this:
http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation
I've never really used threading before in C# where I need to have two threads, as well as the main UI thread. Basically, I have the following.
public void StartTheActions()
{
// Starting thread 1....
Thread t1 = new Thread(new ThreadStart(action1));
t1.Start();
// Now, I want for the main thread (which is calling `StartTheActions` method)
// to wait for `t1` to finish. I've created an event in `action1` for this.
// The I wish `t2` to start...
Thread t2 = new Thread(new ThreadStart(action2));
t2.Start();
}
So, essentially, how can I have a thread wait for another one to finish? What is the best way to do this?
I can see five options available:
1. Thread.Join
As with Mitch's answer. But this will block your UI thread, however you get a Timeout built in for you.
2. Use a WaitHandle
ManualResetEvent is a WaitHandle as jrista suggested.
One thing to note is if you want to wait for multiple threads: WaitHandle.WaitAll() won't work by default, as it needs an MTA thread. You can get around this by marking your Main() method with MTAThread - however this blocks your message pump and isn't recommended from what I've read.
3. Fire an event
See this page by Jon Skeet about events and multi-threading. It's possible that an event can become unsubcribed between the if and the EventName(this,EventArgs.Empty) - it's happened to me before.
(Hopefully these compile, I haven't tried)
public class Form1 : Form
{
int _count;
void ButtonClick(object sender, EventArgs e)
{
ThreadWorker worker = new ThreadWorker();
worker.ThreadDone += HandleThreadDone;
Thread thread1 = new Thread(worker.Run);
thread1.Start();
_count = 1;
}
void HandleThreadDone(object sender, EventArgs e)
{
// You should get the idea this is just an example
if (_count == 1)
{
ThreadWorker worker = new ThreadWorker();
worker.ThreadDone += HandleThreadDone;
Thread thread2 = new Thread(worker.Run);
thread2.Start();
_count++;
}
}
class ThreadWorker
{
public event EventHandler ThreadDone;
public void Run()
{
// Do a task
if (ThreadDone != null)
ThreadDone(this, EventArgs.Empty);
}
}
}
4. Use a delegate
public class Form1 : Form
{
int _count;
void ButtonClick(object sender, EventArgs e)
{
ThreadWorker worker = new ThreadWorker();
Thread thread1 = new Thread(worker.Run);
thread1.Start(HandleThreadDone);
_count = 1;
}
void HandleThreadDone()
{
// As before - just a simple example
if (_count == 1)
{
ThreadWorker worker = new ThreadWorker();
Thread thread2 = new Thread(worker.Run);
thread2.Start(HandleThreadDone);
_count++;
}
}
class ThreadWorker
{
// Switch to your favourite Action<T> or Func<T>
public void Run(object state)
{
// Do a task
Action completeAction = (Action)state;
completeAction.Invoke();
}
}
}
If you do use the _count method, it might be an idea (to be safe) to increment it using
Interlocked.Increment(ref _count)
I'd be interested to know the difference between using delegates and events for thread notification, the only difference I know are events are called synchronously.
5. Do it asynchronously instead
The answer to this question has a very clear description of your options with this method.
Delegate/Events on the wrong thread
The event/delegate way of doing things will mean your event handler method is on thread1/thread2 not the main UI thread, so you will need to switch back right at the top of the HandleThreadDone methods:
// Delegate example
if (InvokeRequired)
{
Invoke(new Action(HandleThreadDone));
return;
}
Add
t1.Join(); // Wait until thread t1 finishes
after you start it, but that won't accomplish much as it's essentialy the same result as running on the main thread!
I can highly recommended reading Joe Albahari's Threading in C# free e-book, if you want to gain an understanding of threading in .NET.
If using from .NET 4 this sample can help you:
class Program
{
static void Main(string[] args)
{
Task task1 = Task.Factory.StartNew(() => doStuff());
Task task2 = Task.Factory.StartNew(() => doStuff());
Task task3 = Task.Factory.StartNew(() => doStuff());
Task.WaitAll(task1, task2, task3);
Console.WriteLine("All threads complete");
}
static void doStuff()
{
// Do stuff here
}
}
From: Create multiple threads and wait all of them to complete
The previous two answers are great and will work for simple scenarios. There are other ways to synchronize threads, however. The following will also work:
public void StartTheActions()
{
ManualResetEvent syncEvent = new ManualResetEvent(false);
Thread t1 = new Thread(
() =>
{
// Do some work...
syncEvent.Set();
}
);
t1.Start();
Thread t2 = new Thread(
() =>
{
syncEvent.WaitOne();
// Do some work...
}
);
t2.Start();
}
ManualResetEvent is one of the various WaitHandle's that the .NET framework has to offer. They can provide much richer thread synchronization capabilities than the simple, but very common tools like lock()/Monitor, Thread.Join, etc.
They can also be used to synchronize more than two threads, allowing complex scenarios such as a 'master' thread that coordinates multiple 'child' threads, multiple concurrent processes that are dependent upon several stages of each other to be synchronized, etc.
You want the Thread.Join() method, or one of its overloads.
I would have your main thread pass a callback method to your first thread, and when it's done, it will invoke the callback method on the mainthread, which can launch the second thread. This keeps your main thread from hanging while its waiting for a Join or Waithandle. Passing methods as delegates is a useful thing to learn with C# anyway.
This implementation is a little different from #jrista's example based on ManualResetEvent as it shows how the various options are like a red or green traffic light.
public System.Threading.AutoResetEvent thread1done = new System.Threading.AutoResetEvent(false);
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
{
thread1done.Set(); //set traffic light to green before threading
StartTheActions();
}
public void StartTheActions()
{
Thread t1 = new Thread(action1);
t1.Start();
thread1done.WaitOne(); //traffic light is red, until thread1done.Set inside action1()
Thread t2 = new Thread(action2);
t2.Start();
}
public void action1()
{
Thread.Sleep(5000);
//.... do some work
thread1done.Set(); //work is done, set traffic light to green at thread1done.WaitOne()
}
public void action2()
{
MessageBox.Show("Now processing action2");
}
Try this:
List<Thread> myThreads = new List<Thread>();
foreach (Thread curThread in myThreads)
{
curThread.Start();
}
foreach (Thread curThread in myThreads)
{
curThread.Join();
}
When I want the UI to be able to update its display while waiting for a task to complete, I use a while-loop that tests IsAlive on the thread:
Thread t = new Thread(() => someMethod(parameters));
t.Start();
while (t.IsAlive)
{
Thread.Sleep(500);
Application.DoEvents();
}
I took a little different approach. There is a counter option in previous answers, and I just applied it a bit differently. I was spinning off numerous threads and incremented a counter and decremented a counter as a thread started and stopped. Then in the main method I wanted to pause and wait for threads to complete I did.
while (threadCounter > 0)
{
Thread.Sleep(500); // Make it pause for half second so that we don’t spin the CPU out of control.
}
This is documented in my blog post: http://www.adamthings.com/post/2012/07/11/ensure-threads-have-finished-before-method-continues-in-c/
Another method is using lock(someObject) and Monitor.Wait(someObject[,timeout]) in one thread and lock(someObject) and Monitor.Pulse(someObject) in another thread. SomeObject has to be the same instance of a class in all 4 calls. SomeObject can't be a struct.
The first thread locks someObject and then calls Monitor.Wait() which releases the lock, so the second thread can lock someObject. When the second thread is finished it calls Monitor.Pulse(), and then the first thread's Monitor.Wait() ends.
Example: someObject is a queue, the first threads waits for the second to put an object in the queue and then dequeues that object.