【问题标题】:Waiting for an event-raising thread to cancel等待事件引发线程取消
【发布时间】:2014-06-16 11:25:14
【问题描述】:

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

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 等待 WorkFinished 事件,然后再处理工作人员。

【问题讨论】:

  • 您使用的是哪个 C# 版本?使用 await 这并不难。
  • 为什么不加入cancel方法?
  • 我想我没听懂你的意思。如果您调用Cancel,那么它将退出循环但仍会调用OnWorkFinished。你不想丢弃什么?
  • usr:我使用的是 C# 4.0。我玩了一点async/await,但我对它不是很有信心。您的意思是等待WorkFinished 事件然后调用Dispose? Vadim:当工作线程引发ProgressMade 事件并等待它被处理时,它会导致死锁。 Yuval:我想避免工人在离开 for 循环之前被处置的情况。它从文件中读取数据并Dispose 关闭文件。

标签: c# multithreading events cancellation


【解决方案1】:

在 cmets 中,您暗示您可以使用 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;
}
}

(快速拍打在一起。)注意,所有等待操作都使用等待。它们释放 UI 线程而不中断您的控制流。

另请注意,MyWorker 是可合作取消的。它对用户界面一无所知。

【讨论】:

  • +1:是的,我每次都会投票支持基于取消令牌的方法。
猜你喜欢
  • 2013-03-02
  • 1970-01-01
  • 2012-09-09
  • 1970-01-01
  • 2020-10-04
  • 1970-01-01
  • 2011-07-21
  • 1970-01-01
  • 2012-06-13
相关资源
最近更新 更多