【问题标题】:Start and stop(forced) a threaded job启动和停止(强制)线程作业
【发布时间】:2011-02-28 18:46:25
【问题描述】:

我想知道启动和停止强制和非强制线程作业的正确方法。这是停止线程的正确方法吗?

    public class ProcessDataJob : IJob
    {
        private ConcurrentQueue<byte[]> _dataQueue = new ConcurrentQueue<byte[]>();
        private volatile bool _stop = false;
        private volatile bool _forceStop = false;
        private Thread _thread;
        private int _timeOut = 1000;

        public void Start()
        {
            _stop = false;
            _forceStop = false;

            _thread = new Thread(ProcessData);
            _thread.Start();
        }

        private void ProcessData()
        {
            while (!_stop || _dataQueue.Count > 0)
            {
                if(_forceStop) return;

                byte[] data;
                if(_dataQueue.TryDequeue(data))
                {
                   //Process data
                   //.....//
                }
            }
        }

        public void Stop(bool force)
        {
            _stop = true;
            _forceStop = force;
            _thread.Join(_timeOut); 
        }

        public void Enqueue(byte[] data)
        {
            _dataQueue.Enqueue(data);
        }
    }

【问题讨论】:

    标签: c# .net multithreading


    【解决方案1】:

    没有正确的方法可以强行杀死一个线程。

    有几种方法可以做到这一点,但没有一种方法是正确的

    仅当您需要终止程序或卸载包含该线程的 appdomain 并且不关心任何处于损坏/错误/锁定状态的数据结构时,您才应该执行强制终止线程,因为他们也会在短时间内消失。

    互联网上有很多关于 Thread.Abort 有多糟糕/邪恶的建议,所以不要这样做。

    相反,编写适当的协作线程。线程应该自己检查一个标志(事件、volatile bool 字段等),然后在收到很好的请求时自愿退出。

    这是正确的方式。

    【讨论】:

    • +1 我完全同意你的看法,而且 OP 已经这样做了 :-) 那么,什么时候可以考虑使用 Thread.Abort?也许永远不会?
    • 如果您需要卸载应用程序域(想想杀死一个正在运行的扩展程序/插件)或退出程序,并且您知道/不关心正在运行的线程未配置 IsBackground 属性。基本上,您想快速摆脱应用程序域/应用程序,并且不想正确等待所有线程自行退出。不过,老实说,即使在那种情况下,我可能仍然不会使用 Thread.Abort。把它当成一个操作系统的功能,对于我们这些凡人来说,基本上是太低级了。让 Eric Lippert 和他的人来处理。
    • 是的,为此我会使用AppDomain.Unload(在幕后使用Thread.Abort)。
    【解决方案2】:

    这是我过去的做法,但有一点不同。过去我有线程意外挂起,这意味着你的那个循环没有得到答案。为了解决这个问题,我让所有线程都使用类,比如你的类,注册一个“经理”类,该类负责参与强制停止等关键事项。线程类具有对管理器的引用,当强制停止完成时,它会调用管理器上的一个方法,该方法实际上是一个计时器。如果到计时器关闭时,线程类尚未将状态标志设置为 STOPPED,则管理器对其调用 abort。

    对我来说,关键不只是呼叫“停止”,而是确认“停止”已经发生,并理解这将是一个不确定的时间量,但“在合理的时间量之后”我应该放弃并继续前进。

    【讨论】:

      【解决方案3】:

      您可以使用 .NET ThreadPool 类,这样您就不必自己处理堆栈。

      【讨论】:

      • 不是一个好的答案。这里没有堆栈(要管理)。而且对于 TP 来说,这似乎是一项太长的工作。
      • @Henk - 您可以通过调用 QueueUserWorkItem 来替换所有这些。在 Gergroen 的情况下可以吗?我们不能说,但这也许值得。
      • 将其推送到 TP 不会使循环和停止(-问题)消失。
      • @Henk - 嗯.. 我以为他正在寻找一种停止线程的好方法。我没有听懂“强迫”这个词。我想我看到了“正确方式”这些术语,无法想象它们被“强迫”放在一边……而且我绝对不明白 Abort 是“正确方式”的正确答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-22
      • 1970-01-01
      相关资源
      最近更新 更多