1

大家好,我用这样的代码开始线程:

    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();
        }
    }

如果我的情况变为真,如何阻止所有这些

4

6 回答 6

21

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

CLR 保证其内部数据结构不会被线程中止破坏。这是 CLR 对线程中止做出的唯一 (*) 保证。它特别不保证

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

如果我不清楚:中止线程非常危险,只有在所有替代方案都更糟时才应该这样做。

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

首先,不要那样做。首先不要启动线程。以取消令牌开始 a Task<T>,当您想将其关闭时,发出其取消令牌的信号。

如果您确实必须启动一个线程,则启动该线程,以便有某种机制使主线程和工作线程可以干净而安全地通信“我希望您此时干净地关闭自己”。

如果您不知道如何做到这一点,那么请停止编写多线程代码,直到您学会如何做到这一点。


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

于 2013-02-11T17:52:41.837 回答
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
    }
}
于 2013-02-11T17:27:50.203 回答
2

您可以使用 aCancellationToken来指示操作何时停止。

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

  2. 在您的后台方法中,定期检查令牌源中的IsCancellationRequested属性,或者如果您希望它在取消时抛出异常,则调用它。TokenThrowIfCancellationRequested()

  3. 当您想停止Cancel对令牌源的线程调用时。

于 2013-02-11T17:46:15.583 回答
1

如果您想知道如何优雅地终止线程,我建议您查看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.");
    }
}
于 2013-02-11T17:31:59.830 回答
0

这是 Windows 窗体代码,其中:

  • 1)点击开始按钮,主线程创建另一个线程
  • 2)再次创建线程创建更多线程。
  • 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++;                
            }
        }     
    }
    

    }

于 2018-02-07T06:59:03.857 回答
-5

简单的答案是使用线程 Abort() 方法,但是您的代码并没有真正说明什么条件,

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

于 2013-02-11T17:30:37.323 回答