通知任务完成

本文关键字:任务 通知 | 更新日期: 2023-09-27 17:58:08

我在想一种简单的方法来对完成任务做出反应。我想出了以下解决方案(用一个按钮将其粘贴到WinForms应用程序中进行测试):

public partial class Form1 : Form
{
    private Thread thread;
    public void DoFinishWork() {
        // [4] 
        // UI thread - waiting for thread to finalize its work
        thread.Join();
        // Checking, if it really finished its work
        MessageBox.Show("Thread state: " + thread.IsAlive.ToString());
    }
    public void DoWork() {
        // [2]
        // Working hard
        Thread.Sleep(1000);
    }
    public void FinishWork() {
        // [3]
        // Asynchronously notifying form in main thread, that work was done
        Delegate del = new Action(DoFinishWork);
        this.BeginInvoke(del);
        // Finalizing work - this should be switched
        // at some point to main thread
        Thread.Sleep(1000);
    }
    public Form1()
    {
        InitializeComponent();
    }
    private void button1_Click(object sender, EventArgs e) {
        // [1]
        // Schedule the task
        ThreadStart start = new ThreadStart(DoWork);
        // Schedule notification about finishing work
        start += FinishWork;
        thread = new Thread(start);
        thread.Start();
    }
}

这是一个简单的取消场景,因此只有一个线程,它将与UI线程并行运行。

有没有一种更简单(或更线程安全)的方式来实现Thread的这种通知?

请考虑两个事实:

  • i可以终止线程的唯一方法是Abort(这是因为我无法控制线程中正在执行的操作-第三方代码)
  • 因此,我不能使用BackgroundWorker,因为它只提供优美终止的方式

通知任务完成

有没有一种更简单(或更线程安全)的方法来实现线程的这种通知?

是的,使用TPL,让框架担心管理线程

Task.StartNew(() => {
   // do some stuff
}).ContinueWith((task) => {
   // do some stuff after I have finished doing some other stuff
});

或者,由于您正在使用WinForms,请使用BackgroundWorker并处理RunWorkerCompleted事件

我把kill的概念误认为cancel-在.NET中没有可靠的方法来实际杀死线程,甚至文档也表明使用Abort或多或少是一场赌博,并且绝对不能保证线程会被杀死。此外,这将使线程和应用程序处于不可预测的状态,因此,如果您愿意承担风险,那就由您自己决定了。

一种选择是简单地让线程播放,但忽略结果,这取决于任务的大小,可能没什么大不了的。

尽管您需要Abort来杀死线程,但您仍然可以使用TPL。您可以在任务中启动该线程,并等待它以及CancellationToken。当任务在线程完成之前被取消时,您可以在线程上调用Abort

它看起来像这样:

// In your class:
ManualResetEvent threadFinished = new ManualResetEvent(false);
// In your calling function (button1_Click):
Task.Run( () => {
    ThreadStart threadStart = new StreadStart(DoWork);
    threadStart += () => { threadFinished.Set(); }
    Thread thread = new Thread(threadStart);
    threadFinished.Reset();
    thread.Start();
    WaitHandle waitCancel = cancellationToken.WaitHandle;
    int waited = WaitHandle.WaitAny( new WaitHandle[]{ waitCancel, threadFinished } );
    if (waited == 0 && cancellationToken.IsCancellationRequested)
        thread.Abort();
    else
        thread.Join()
});