如何阻止线程?

时间:2013-02-11 17:25:36

标签: c# multithreading

大家好我用这样的代码启动线程:

    Thread[] thr;
    private void button1_Click(object sender, EventArgs e)
    {
        decimal value = numericUpDown2.Value;
        int i = 0;
        threads_count = (int)(value);
        thr = new Thread[threads_count];
        for (; i < threads_count; i++)
        {
            thr[i] = new Thread(new ThreadStart(go));
            thr[i].IsBackground = true;
            thr[i].Start();
        }
    }

如果条件成真,如何阻止所有这些

6 个答案:

答案 0 :(得分:21)

许多答案说中止线程。 除非是紧急情况并且您正在关闭应用程序,否则永远不要中止线程

CLR保证其内部数据结构不会被线程中止损坏。 这是CLR针对线程中止提供的唯一(*)保证。它特别保证:

  • 线程实际上会中止。线程可以强化自己不被终止。
  • CLR本身中的任何数据结构都不会被破坏。在关键操作中间的线程中止可以使BCL数据结构或用户数据结构处于任意不一致的状态。这可能会在以后神秘地崩溃您的过程。
  • 那个锁会被释放。中止线程可能会导致锁永远存在,它可能导致死锁,等等。

如果我不清楚:中止线程是非常危险的你应该只在所有替代方案都更糟的情况下这样做。

那么如果你想启动一个线程然后干净地关闭它呢?

首先,不要这样做。首先不要启动线程。使用取消令牌启动Task<T>,当您想要将其关闭时,请发出取消令牌信号。

如果你必须启动一个线程,那么启动线程,以便有一些机制,主线程和工作线程可以干净利落地安全地沟通“我希望你此时干净利落地关闭自己”。

如果您不知道如何操作,那么将停止编写多线程代码,直到您了解如何执行此操作。


(*)这是一个小谎言; CLR还对线程中止和特殊代码区域(如约束执行区域和最后块)的交互做出了某些保证。

答案 1 :(得分:2)

野蛮方式(不推荐) - 使用Thread.Abort方法中止线程。此方法在线程上引发ThreadAbortException。像这样:

foreach(Thread thread in thr)
    thread.Abort();

但更好的方法是通知线程取消并让它正确完成其工作。您只需使用.Net 4任务即可完成此操作:

Task[] thr = new Task[threads_count];
var source = new CancellationTokenSource();

for (int i = 0; i < threads_count; i++)
{
    thr[i] = Task.Factory.StartNew(go, source.Token);
}

// later, when condition is met
source.Cancel();

以下是取消应该如何:

private static void go(object obj)
{
    CancellationToken token = (CancellationToken)obj;
    while (true)
    {
        if (token.IsCancellationRequested)
            return;

        // do some work
    }
}

答案 2 :(得分:2)

您可以使用CancellationToken发出操作停止时的信号。

  1. 创建一个CancellationTokenSource作为您在按钮点击处理程序中初始化的类型的实例字段。

  2. 在您的后台方法中,定期检查令牌源中IsCancellationRequested的{​​{1}}属性,如果您希望它只是抛出异常,则调用Token取消。

  3. 如果要停止线程,请在令牌源上调用ThrowIfCancellationRequested()

答案 3 :(得分:1)

如果您想知道如何优雅地终止线程,我建议您查看以下example on MSDN

using System;
using System.Threading;

public class Worker
{
    public void DoWork()
    {
        while (!_shouldStop)
        {
            Console.WriteLine("worker thread: working...");
        }
        Console.WriteLine("worker thread: terminating gracefully.");
    }
    public void RequestStop()
    {
        _shouldStop = true;
    }
    // Volatile is used as hint to the compiler that this data
    // member will be accessed by multiple threads.
    private volatile bool _shouldStop;
}

public class WorkerThreadExample
{
    static void Main()
    {
        Worker workerObject = new Worker();
        Thread workerThread = new Thread(workerObject.DoWork);
        workerThread.Start();
        Console.WriteLine("main thread: Starting worker thread...");

        while (!workerThread.IsAlive); // Loop until worker thread activates

        // Put the main thread to sleep for 1 millisecond to
        // allow the worker thread to do some work:
        Thread.Sleep(1);

        workerObject.RequestStop();

        // Use the Join method to block the current thread 
        // until the object's thread terminates.
        workerThread.Join();
        Console.WriteLine("main thread: Worker thread has terminated.");
    }
}

答案 4 :(得分:0)

这是Windows Form Code,其中包含:

  • 1)在单击开始按钮上,主线程创建另一个线程
  • 2)再次创建Thread在更多线程上创建。
  • 3)单击“停止”按钮,首先应该终止最后一个线程然后由主线程创建的线程应该终止。

    namespace Thread_TerminateProblem
    {    
        public partial class Form1 : Form
        {     
    
    
        private static AutoResetEvent m_ResetEvent = null;                
        private static ManualResetEvent m_ResetEvent_Thread = new ManualResetEvent(false);
        enum ServiceState { Start, Stop };
        bool flag = false;
        int x = 0;
        ServiceState _state;
        public Form1()
        {
            InitializeComponent();
        }
    
        private void btnStart_Click(object sender, EventArgs e)
        {
            flag = true;
            _state = ServiceState.Start;
            m_ResetEvent = new AutoResetEvent(true);            
            Thread t1 = new Thread(fun_Thread1);
            t1.Start();
            t1.Name = "Thread1";            
        }
    
        private void btnStop_Click(object sender, EventArgs e)
        {
            _state = ServiceState.Stop;
            m_ResetEvent.Set();           
        }
    
    
        private void fun_Thread1()
        {
            while (true)
            {                               
                m_ResetEvent.WaitOne();                
                switch (_state)
                {
                    case ServiceState.Start:
                        {                            
                            Thread t = new Thread(fun_Thread2);
                            t.Start();
                            t.Name = "Thread2";
                            break;
                        }
                    case ServiceState.Stop:
                        {
                            m_ResetEvent_Thread.Set();
                            flag = true;
                            break;
                        }
                }
                // When the child Thread terminates, Then only this thread should terminate
                if (flag == true)
                {
                    // Waiting for notification from child Thread
                    notifyParent.WaitOne();
                    Thread.Sleep(100);
                    break;
                }                
                m_ResetEvent.Reset();                              
            }            
        }
    
        private static ManualResetEvent notifyParent = new ManualResetEvent(false);
    
        private void fun_Thread2()
        {
            while (true)
            {
                if (m_ResetEvent_Thread.WaitOne(1, false))
                {
                    notifyParent.Set();
                    break;
                }
                x++;                
            }
        }     
    }
    

    }

答案 5 :(得分:-5)

简单的回答是使用线程Abort()方法然而你的代码并没有真正说清楚什么条件,

什么循环测试与条件?为什么你需要中止一个线程?我问,因为可能有更好的方法来解决这个问题