简体   繁体   English

如何等待线程完成工作

[英]How to wait for a thread to finish its work

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. 一个类(例如,Worker)在单独的线程中执行某些工作,并在完成时引发事件。 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. 编辑:更正了语句的顺序,但这不是问题。

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. 好的,问题已被修改,因此您似乎真正要问的是如何等待PostProcess完成执行。 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, eg assuming the thread is exposed as a property: 最简单的方法是,因为事件总是在引发事件的同一线程上执行,所以在Worker类创建的线程上调用Thread.Join ,例如,假定该线程公开为属性:

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). (虽然说实话,我可能会保持Thread私有,并在Worker类上公开一个名为WaitForCompletion之类的方法,以调用该方法)。

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. Worker类中有一个WaitHandle ,可能是ManualResetEvent ,在完成所有工作时将其SetSet ,然后在其上调用WaitOne

  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). Worker类中有一个volatile bool complete字段,并在循环主体中使用Thread.Sleep等待它设置为true ,然后循环(这可能不是一个好的解决方案,但可行)。

There are probably other options too, but that's the common ones. 可能还有其他选择,但这是常见的选择。

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. WorkCompleted是事件处理程序,必须预先设置。 This does not get invoked by the assignment worker.WorkCompleted += PostProcess; 工作分配不会调用此方法。WorkCompleted + = PostProcess;

Use WaitHandle class members (WaitOne, WaitAny, or WaitAll) 使用WaitHandle类成员(WaitOne,WaitAny或WaitAll)

See Details Here In MSDN 在MSDN中查看详细信息

The Worker class should have a method that allows the client to wait for the thread to complete. Worker类应具有允许客户端等待线程完成的方法。 That method would call the appropriate overload of Thread.Join() to implement the wait. 该方法将调用Thread.Join()的适当重载以实现等待。 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. 如果没有(您没有办法修改Worker类),则它可能有一些方法可以访问内部Thread对象,您可以对该对象执行Join()。

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. 如果两者都不具备,则需要查看(和/或在此处张贴) Worker类接口的更多详细信息,以查看其是否具有适当的方法来等待完成。 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. 如果没有它,那么您将需要自己的EventWaitHandle对象, PostProcess()事件处理程序可以在调用该对象时发出信号。

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: 假设您无权访问Worker类,只需添加一个标志,该标志指示PostProcessing何时完成并进入睡眠状态,直到设置了该标志:

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. 这应该可以解决问题,但是如果您不提供有关安装的更多信息,就无法保证它的强大功能。

You could use the BackgroundWorker class from the .net framework for this. 您可以为此使用.net框架中的BackgroundWorker类。

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

This sounds like a good candidate of using the Begin/End asynchronous pattern in your worker. 这听起来像是在工作线程中使用Begin / End异步模式的不错选择。 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. 因此, Worker包括开始异步执行工作的DoWork()方法和在工作完成时触发的事件,还包括同步的Work()方法(该方法返回Work()结果)和BeginWork()和可以用于异步使用的EndWork()对。

See http://msdn.microsoft.com/en-us/library/seta58yd(VS.71).aspx for some more information about this. 有关此问题的更多信息,请参见http://msdn.microsoft.com/zh-cn/library/seta58yd(VS.71).aspx Might be a good fit for your situation? 可能适合您的情况吗?

I think Application.Run after initializing your thread. 我认为Application.Run初始化线程后。 and on completion call Application.Exit 然后在完成时调用Application.Exit

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM