通知任务完成
本文关键字:任务 通知 | 更新日期: 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()
});