【问题标题】:Passing exception or message from thread/task to main thread将异常或消息从线程/任务传递到主线程
【发布时间】:2012-05-30 15:24:30
【问题描述】:

我们正在处理 Windows 服务 (.net 4.0) 中大文件的处理和上传。处理和上传步骤可能需要几分钟才能完成。管理员可以直接在数据库中将作业标记为已取消,但要在内存队列中清除它需要重新启动服务。目标是放弃该作业并在队列中选择下一个作业,而无需重新启动服务。这是我想做的:

在主入口点,启动两个任务:

Task processTask = Task.Factory.StartNew(ProcessJob);

Task monitorTask = Task.Factory.StartNew(MonitorDB);

ProcessJob 会调用多个长时间运行的步骤,例如 ProcessFile、UploadFile。我们正在检查步骤之间的作业状态,但作业可能会停留在这些长时间运行的步骤之一中。

如果 monitorTask 检测到 DB 中的作业状态更改,它应该将其传达给主线程(通过异常或消息),以便主线程可以退出,将自己从处理队列中移除并允许队列中的下一个作业开始。没有等待不能得到异常但不能等待,因为需要并行运行这些任务。 目前,我们并不关心 ProcessJob 中的某些同步步骤可能仍在进行并最终可能完成的事实。我们将在代码中处理它。

到目前为止,在我的所有应用程序中,我都使用 Task.ContinueWith 来判断成功和失败,但从来不需要与主线程进行通信。

【问题讨论】:

    标签: c# multithreading task-parallel-library task


    【解决方案1】:

    您可以通过BlockingCollection<T> 在监视器线程和主线程之间进行通信。

    这是我写的一个简单的例子。

    BlockingCollection<string> queue =
        new BlockingCollection<string>();
    
    // monitor thread.
    Task.Factory.StartNew(() =>
    {
        while (true)
        {
            Thread.Sleep(1000);
            queue.Add("event occured.");
        }
    });
    
    // main thread.
    while (true)
    {
        // blocks when no messages are in queue.
        string message = queue.Take();
    
        // kill process thread here.
    }
    

    【讨论】:

    • 谢谢@jborg。它有帮助。顺便说一句,我也意识到我可以在这两个任务上使用 WaitAny 来实现类似的结果,然后检查哪一个完成/出错。我在测试应用程序中同时拥有这两个。
    【解决方案2】:

    您可以为此使用CancellationToken。如果您查看Task 类,您可以在其中传递CancellationToken 的重载。在您的服务中存储对此令牌的引用,并让您的上传/处理例程定期检查令牌是否已被取消,如下所示:

    if (yourToken.IsCancellationRequested)
        break;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-25
      • 2014-08-04
      • 2011-01-18
      • 1970-01-01
      • 2019-09-16
      • 1970-01-01
      相关资源
      最近更新 更多