【问题标题】:Cancel ThreadPool .QueueUserWorkItem Task取消 ThreadPool .QueueUserWorkItem 任务
【发布时间】:2011-10-11 19:44:03
【问题描述】:

我需要取消使用 ThreadPool.QueueUserWorkItem(...) 启动的后台任务。我知道 BackgroundWorker 有专门针对这类事情的构造,但我认为在这种情况下它是矫枉过正的,因为不涉及用户界面。通过取消,我的意思是强制完成回调方法。

在我的课程中添加类似以下内容的陷阱是什么?

// Cancellation Property.
private bool _canceled;
public bool CancelTask
{
    get { return _canceled; }
    set { _canceled = value; }
}

public void DoSomeTask()
{
    int iterations = 50;
    ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadPoolCallback), iterations);
}

private void ThreadPoolCallback(object state)
{
    if (_canceled)
        return; // don't even start.

    int iterations = (int)state;
    for (int i = 0; !_canceled && i < iterations; i++)
    {
        //
        // do work ...
        //

        // This allows you to cancel in the middle of an iteration...
        if (_canceled)
            break;
    }
}

有没有更好的办法?

【问题讨论】:

  • 我已经多次使用类似的技术,没有任何问题;我看到的唯一问题是,如果多个线程可能会尝试写入_canceled。但是对于一个简单的“写一次,读一次,退出”的标志,我从来没有遇到过问题。不过,我很想听听其他想法。
  • 只要确保 _canceled 正确同步即可。我建议使用联锁函数来修改该变量,以便存在内存屏障。
  • 您必须对 _canceled 成员声明使用 volatile 使用 CancelTask​​ 属性 getter。没有这个,你的工作方法很可能永远不会看到更新。 BGW 的开销很小,支持经过数千人测试并由其他人维护的代码。
  • 你可以使用 .NET 4.0 吗?如果可以,您可以使用 TPL。它对取消机制有很好的支持。
  • @Bryan -- 还没有,我们正在使用 .NET 2.0。

标签: c# threadpool cancellation


【解决方案1】:

我会使用方法 CancelTask​​() 而不是属性。关键是调用者应该能够取消任务,但没有人应该能够取消取消任务。

然后您需要确保 _cancelled 的读取和写入具有适当的内存屏障,否则一个线程可能永远不会观察到另一个线程所做的更改。为此,我将使用 Thread.VolatileWrite(在 CancelTask​​ 内)和 Thread.VolatileRead(在您的循环内)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-01
    • 1970-01-01
    • 2011-07-10
    • 1970-01-01
    • 2014-06-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多