0

I have a console application. A class (let's say Worker) does some work in a separate thread and throws an event when it finishes. But this never happens because the execution ends instantly. How can I wait for the thread to finish and handle the event after it throws?

static void Main(string[] args) { Worker worker = new Worker(); worker.WorkCompleted += PostProcess; worker.DoWork(); } static void PostProcess(object sender, EventArgs e) { // Cannot see this happening } 

Edit: Corrected the order of the statements but that was not the problem.

8 Answers 8

15

You've got a race condition, in that the work could finish before you register for the event. To avoid the race condition, change the order of the code so you register for the event before starting the work, then it will always be raised, no matter how fast it finishes:

static void Main(string[] args) { Worker worker = new Worker(); worker.WorkCompleted += PostProcess; worker.DoWork(); } 

Edit:

OK the question has been modified, so it looks like what you're really asking is how to wait for PostProcess to finish executing. There are a couple of ways to do this, but you'll have to add some more code.

The easiest way is, because events always execute on the same thread as they are raised, is to call Thread.Join on the thread the Worker class creates, e.g. assuming the thread is exposed as a property:

worker.Thread.Join(); 

(Although to be honest I'd probably keep the Thread private and expose a method called something like WaitForCompletion on the Worker class that calls it).

Alternative methods are:

  1. Have a WaitHandle, probably a ManualResetEvent, in the Worker class which is Set when it completes all its work, and call WaitOne on it.

  2. Have a volatile bool complete field in the Worker class and loop while waiting for it to be set to true, using Thread.Sleep in the loop body (this probably isn't a good solution, but it is feasible).

There are probably other options too, but that's the common ones.

Sign up to request clarification or add additional context in comments.

2 Comments

here i have seen there is built in class called Worker but i found no class called Worker in .net 4.0. which version has class Worker? please let me know.
@Thomas - The Worker class was just the name of the class used by the OP. I assume that it is part of their framework.
2

Use WaitHandle class members (WaitOne, WaitAny, or WaitAll)

See Details Here In MSDN

Comments

2

Have you tried switching the order of the statements ?

static void Main(string[] args) { Worker worker = new Worker(); worker.WorkCompleted += PostProcess; worker.DoWork(); } 

WorkCompleted is an event handler and has to be set up-front. This does not get invoked by the assignment worker.WorkCompleted += PostProcess;

1 Comment

Thanks, but it is correct in my real code, that is not the problem.
0

The Worker class should have a method that allows the client to wait for the thread to complete. That method would call the appropriate overload of Thread.Join() to implement the wait. If it doesn't (and you have no way to modify the Worker class), it may have some method to get to the internal Thread object and you can perform the Join() on that object.

If it has neither of those, you'll need to look at (and/or post here) more details of the Worker class interface to see if it has an appropriate method to wait for completion. If it doesn't have one, then you'll need your own EventWaitHandle object that the PostProcess() event handler can signal when it gets invoked.

2 Comments

Worker class has no Join method. What is it supposed to do?
Sorry - I answered as if the worker object was an object of the Thread class. I've amended my answer to be more generic.
0

Assuming you have no access to the Worker class, just add a flag that indicates when PostProcessing has done and sleep until the flag is set:

static bool isProcessed = false; static void Main(string[] args) { Worker worker = new Worker(); worker.WorkCompleted += PostProcess; worker.DoWork(); while(!isProcessed) { System.Threading.Thread.Sleep(-1); } } static void PostProcess(object sender, EventArgs e) { // Cannot see this happening isProcessed=true; } 

THis should do the trick, but I can't guarantee that it is robust without more information on your setup.

2 Comments

That is manual code and wastage of CPU to wait for processing to complete. WaitHandles are meant to tackle these situations.
I actually have no idea what the behavior of WaitHandle is when it is only signaled from the blocking thread, and I was too lazy to test it. I had assume PostProcess executes on the blocked thread. Without more information this was an easy solution that works.
0

You could use the BackgroundWorker class from the .net framework for this.

It does exactly what you want to do. In addition it handles invoking itself so no pain for you with this.

static void Main(string[] args) { BackgroundWorker worker = new BackgroundWorker(); worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged); worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); worker.WorkerReportsProgress = true; worker.WorkerSupportsCancellation = false; worker.DoWork += new DoWorkEventHandler(MyThreadMethod); worker.RunWorkerAsync(); Console.Read(); } static void MyThreadMethod(object sender, DoWorkEventArgs e) { Console.WriteLine("Worker starts working."); for (int i = 1; i <= 100; i++) { ((BackgroundWorker)sender).ReportProgress(i); } Console.WriteLine("Worker works fine."); } static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { Console.WriteLine("Worker has finished."); } static void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { Console.WriteLine("Worker reports progress {0}", e.ProgressPercentage); } 

Comments

0

I think Application.Run after initializing your thread. and on completion call Application.Exit

Comments

0

This sounds like a good candidate of using the Begin/End asynchronous pattern in your worker. So instead of just a DoWork() method that starts to do the work asynchronously and an event that fires when the work is complete, Worker would include a synchronous Work() method that returns the result(s) of the work, and BeginWork() and EndWork() pair that can be used for asynchronous use.

See http://msdn.microsoft.com/en-us/library/seta58yd(VS.71).aspx for some more information about this. Might be a good fit for your situation?

1 Comment

(Assuming you actually wrote or otherwise have access to the source code of the Worker class, of course.)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.