How to wait for a thread to finish its work

I have a console application. A class (say Worker) does some work on a separate thread and throws an event when it ends. But this never happens, because execution ends instantly. How can I wait for the thread to end and handle the event after it is thrown?

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: Fixed the order of the operators, but that's not a problem.

0


source to share


8 answers


You have a race condition where work may end before you register for the event. To avoid a race condition, change the order of your code so that you register for the event before starting, then it will always be raised no matter how quickly it ends:

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

      


Edit:

OK the question has been changed, so it looks like you are really asking how to wait for completion PostProcess

. There are several ways to do this, but you have to add a few more codes.

The easiest way is that events are always executed on the same thread in which they were raised - this is called Thread.Join

on the thread that creates the class Worker

, for example. if the stream is expanded as a property:



worker.Thread.Join();

      

(Though, to be honest, I would probably keep it Thread

private and expose the method named WaitForCompletion

in the class Worker

that calls it).

Alternative methods:

  • You have WaitHandle

    , perhaps, ManualResetEvent

    in a class Worker

    that is Set

    when it finishes all its work and calls on it WaitOne

    .

  • You have a field volatile bool complete

    in a class and a loop Worker

    , expecting it to be set to true

    using Thread.Sleep

    in the body of the loop (this is probably not a good solution, but it is possible).

Perhaps there are other options, but general ones.

+15


source


Have you tried switching the order of statements?

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

      



WorkCompleted is an event handler and must be configured ahead of time. It will not be triggered by a work assignment. WorkCompleted + = PostProcess;

+2


source


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

See details here on MSDN

+2


source


The Worker class must have a method that allows the client to wait for the thread to complete. This method will call the appropriate overload Thread.Join()

to implement the wait. If it doesn't (and you can't change the class Worker

), it might have some method to access the inner Thread object, and you can do a Join () on that object.

If it does not have any of these, you will need to look (and / or post here) more details on the class interface Worker

to see if it has a suitable method to wait for completion. If it doesn't have one, then you need your own object EventWaitHandle

that the event handler PostProcess()

can signal when it is called.

0


source


Assuming you don't have access to the Worker class, just add a flag that indicates when PostProcessing has completed and hibernate 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 cannot guarantee that it is reliable without further information on your setup.

0


source


You can use a class BackgroundWorker

from the .net framework for this .

It does exactly what you want it to do. Plus, it handles the call, so you don't get hurt with it.

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

      

0


source


This sounds like a good candidate for your worker's Begin / End asynchronous pattern. Therefore, instead of a method DoWork()

that starts working asynchronously and an event that fires when the work is complete, it Worker

will include a synchronous method Work()

that returns the result of the work, and BeginWork()

and EndWork()

, which can be used for asynchronous use.

See http://msdn.microsoft.com/en-us/library/seta58yd(VS.71).aspx for more information on this. Maybe this works well for your situation?

0


source


I think Application.Run after you initialize your thread. and upon completion of the call to Application.Exit

0


source







All Articles