等待事件引发线程取消

本文关键字:线程 取消 事件 等待 | 更新日期: 2023-09-27 18:08:43

我有一个工作线程,它通过引发事件来报告进度。

private volatile bool canRun;
public void Run()
{
    for (int i = 0; i < count && canRun; i++)
    {
        // do stuff
        OnProgressMade((float)i / (float)count);
    }
    OnWorkFinished();
}
public void Cancel()
{
    canRun = false;
    // wait for the thread to finish
}

Cancel方法中,我想等待线程完成。否则,有人可能会调用Cancel,然后立即调用Dispose,而线程仍在"做事情"。如果我使用Join,可能会出现死锁——UI等待线程取消,线程等待UI处理ProgressMade事件。

是否有办法很好地解决这个问题,或者从一开始就是糟糕的设计?我目前的解决方案依赖于UI在处理worker之前等待WorkFinished事件。

等待事件引发线程取消

在评论中你暗示你可能会使用await(这在。net 4.0中也是可能的)。它可以像这样:

MyWorker w;
CancellationTokenSource cts;
void OnStart(eventargs bla bla) {
 cts = new ...();
 w = new ...(cts.Token);
}
void OnCancel(eventargs bla bla) {
 cts.Cancel();
 await w.WaitForShutdown();
 MsgBox("cancelled");
}

我们需要让MyWorker合作:

class MyWorker {
CancellationToken ct = <from ctor>;
TaskCompletionSource<object> shutdownCompletedTcs = new ...();
public void Run()
{
    for (int i = 0; i < count && !ct.IsCancellationRequested; i++)
    {
        // do stuff
        OnProgressMade((float)i / (float)count);
    }
    //OnWorkFinished(); //old
    shutdownCompletedTcs.SetResult(null); //new, set "event"
}
public Task WaitForShutdown() {
 return shutdownCompletedTcs.Task;
}
}

(快速拼凑)注意,所有等待操作都使用await。它们在不中断控制流的情况下释放UI线程。

还要注意,MyWorker是可协作取消的。它对UI一无所知