繁体   English   中英

如何等待线程完成工作

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

我有一个控制台应用程序。 一个类(例如,Worker)在单独的线程中执行某些工作,并在完成时引发事件。 但这永远不会发生,因为执行立即结束。 我如何等待线程完成并在引发事件后对其进行处理?

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 }

编辑:更正了语句的顺序,但这不是问题。

您的比赛条件有限,因为您可以在报名参加比赛之前完成工作。 为了避免争用情况,请更改代码顺序,以便在开始工作之前注册事件,然后无论发生多快,都将始终引发该事件:

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

编辑:

好的,问题已被修改,因此您似乎真正要问的是如何等待PostProcess完成执行。 有两种方法可以执行此操作,但是您必须添加更多代码。

最简单的方法是,因为事件总是在引发事件的同一线程上执行,所以在Worker类创建的线程上调用Thread.Join ,例如,假定该线程公开为属性:

worker.Thread.Join();

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

替代方法是:

  1. Worker类中有一个WaitHandle ,可能是ManualResetEvent ,在完成所有工作时将其SetSet ,然后在其上调用WaitOne

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

可能还有其他选择,但这是常见的选择。

您是否尝试过切换语句的顺序?

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

WorkCompleted是事件处理程序,必须预先设置。 工作分配不会调用此方法。WorkCompleted + = PostProcess;

使用WaitHandle类成员(WaitOne,WaitAny或WaitAll)

在MSDN中查看详细信息

Worker类应具有允许客户端等待线程完成的方法。 该方法将调用Thread.Join()的适当重载以实现等待。 如果没有(您没有办法修改Worker类),则它可能有一些方法可以访问内部Thread对象,您可以对该对象执行Join()。

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

假设您无权访问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;
}

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

您可以为此使用.net框架中的BackgroundWorker类。

它正是您想要做的。 此外,它可以处理调用本身,因此您不会为此感到痛苦。

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

这听起来像是在工作线程中使用Begin / End异步模式的不错选择。 因此, Worker包括开始异步执行工作的DoWork()方法和在工作完成时触发的事件,还包括同步的Work()方法(该方法返回Work()结果)和BeginWork()和可以用于异步使用的EndWork()对。

有关此问题的更多信息,请参见http://msdn.microsoft.com/zh-cn/library/seta58yd(VS.71).aspx 可能适合您的情况吗?

我认为Application.Run初始化线程后。 然后在完成时调用Application.Exit

暂无
暂无

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

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