通知任务完成其工作

时间:2014-04-14 10:01:43

标签: c# multithreading

我正在考虑一种简单的方法来完成任务完成其工作。我提出了以下解决方案(将其粘贴到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实现此类通知?

请考虑两个事实:

  • 可以终止该线程的唯一方法是Abort它(因为我无法控制线程中的内容 - 第三方代码)
  • 因此,我无法使用BackgroundWorker,因为它只提供正常终止的方式。

2 个答案:

答案 0 :(得分:0)

  

是否有更简单(或更多线程安全)的方式为Thread实现此类通知?

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

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

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

我把 kill 的概念误认为取消 - 没有可靠的方法在.NET中实际杀死一个线程,即使documentation建议使用Abort或多或少都是一场赌博,绝对不会让线索真正被杀死。此外,它会留下线程,因此,应用程序处于不可预测的状态,因此如果您愿意冒这个风险,那么这取决于您。

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

答案 1 :(得分:0)

虽然您需要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()

});