启动和停止(强制)一个线程作业

3

我希望了解一种合适的方法来启动和停止强制和非强制线程作业。这是停止线程的正确方式吗?

    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);
        }
    }
3个回答

7

强制终止线程没有适当的方法。

虽然有几种方法可以做到,但都不是适当的

只有在需要终止程序或卸载包含线程的应用程序域并且不关心留下的数据结构处于损坏/错误/锁定状态时才应该强制终止线程,因为它们也将很快消失。

互联网上有很多关于Thread.Abort的坏/邪恶建议,所以不要使用它。

相反,编写适当的协作式线程。线程本身应检查标志(事件、volatile bool字段等),然后在被礼貌地请求退出时自愿退出。

这是适当的方式。


+1 我完全同意你的观点,而且楼主已经在这样做了 :-) 那么,什么情况下才会考虑使用Thread.Abort呢?也许从来不需要使用它? - Jordão
如果您需要卸载应用程序域(类似于终止正在运行的扩展/插件)或退出程序,并且您知道/不关心是否有未配置IsBackground属性的线程正在运行。基本上,您想快速摆脱应用程序域/应用程序,而不想等待所有线程自行退出。虽然,老实说,即使在这种情况下,我可能仍然不会使用Thread.Abort。将其视为操作系统功能,对于我们这些凡人来说,它基本上太低级了。让Eric Lippert和其他人来处理它。 - Lasse V. Karlsen
是的,为此我会使用 AppDomain.Unload (底层使用 Thread.Abort)。 - Jordão

1
这是我过去做的方式,只有一个区别。过去我曾经遇到线程意外挂起的情况,这意味着你那个循环不会返回答案。为了解决这个问题,我让所有使用类似于你的线程类都向一个“管理器”类注册,该类负责参与关键事项,如强制停止。线程类具有对管理器的引用,当执行强制停止时,它调用管理器上的一个方法,该方法实际上是一个计时器。如果在计时器结束时,线程类还没有设置一个状态标志来表示已停止,那么管理器就会调用abort方法。
对我来说,关键的不仅是调用“stop”,而且是确认“stop”已经发生,并理解它将是一个非确定性的时间量,但“在合理的时间内”我应该放弃并继续前进。

0

你可以使用.NET 线程池 类,这样就不必自己处理堆栈。


不是一个好的答案。这里没有堆栈(需要管理)。而且这似乎对 TP 来说是一个太长的工作。 - H H
@Henk - 你可以通过调用QueueUserWorkItem来替换所有这些内容。在Gergroen的情况下,这样做是否可以呢?我们无法确定,但这可能是值得的。 - Simon Mourier
将其推到 TP 上并不能解决循环和停止问题。 - H H
@Henk - 嗯...我以为他在寻找一种优雅的方式来停止线程。我没有注意到“强制”这个词。我想我看到了“正确的方式”这些词,无法想象它们与“强制”有关...而且我绝对不明白中止是“正确的方式”的答案。 - Simon Mourier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接