2013-02-11 106 views
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(); 
     } 
    } 

如何停止所有的人,如果我的条件成为真正的

+3

您可以发布中'go'代码以及 – 2013-02-11 17:27:45

+0

的常用方法停止线程结束的线程中运行代码。 – 2013-02-11 17:30:52

+0

它可能有帮助http://stackoverflow.com/questions/1764898/how-do-i-safely-stop-ac-sharp-net-thread-running-in-a-windows-service – exexzian 2013-02-11 17:34:57

回答

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 
    } 
} 
+3

+1,因为它是这是强制停止线程的唯一方法......并且使线程在终止中协作将会更安全。你真的不想学习Thread.Abort的所有可能的副作用和减轻它们的方式。 – 2013-02-11 17:32:34

+2

我会避免使用'Thread.Abort'来指示线程停止。当线程看到类似'CancellationToken'或布尔标志的东西以安全的方式停止时。但是由于该线程处于可能不受关注的背景中。 – 2013-02-11 17:33:00

+1

同意,放弃线程是一个残酷的解决方案,但它是最简单的解决方案。这里是关于这个问题的问题http://stackoverflow.com/questions/710070/timeout-pattern-how-bad-is-thread-abort-really/710094#710094 – 2013-02-11 17:34:43

-5

简单的答案是,使用线程中止()方法,但您的代码不真的说清楚什么条件,

什么循环测试与条件?为什么你需要中止一个线程?我问的有可能是一个更好的办法。如果你想知道如何优雅地终止线程来处理这个

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."); 
    } 
} 
+2

虽然这可能在理论上回答这个问题,[这将是最好](http://meta.stackexchange.com/q/8259)在这里包含答案的重要部分,并提供供参考的链接。 – Spontifixus 2013-02-11 17:32:49

+0

对不起,我这里相当新。感谢您的鼓舞! – 2013-02-11 17:37:59

2

你可以使用CancellationToken来指示操作何时应该停止。

  1. 创建CancellationTokenSource如您在按钮单击处理程序初始化类的实例字段。

  2. 在你的后台方法定期检查TokenIsCancellationRequested财产令牌源,或致电ThrowIfCancellationRequested()如果你希望它只是抛出一个异常,如果它被取消。

  3. 当您想要停止线程在令牌源上调用Cancel

21

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

CLR保证其内部数据结构不会被线程中止破坏。 这是CLR针对线程中止所做的唯一(*)保证。它具体做不是保证:

  • 线程实际上会中止。线程可以防止被终止。
  • CLR中的任何数据结构而不是本身都不会被破坏。在关键操作的中间线程中止会使BCL数据结构或用户数据结构处于任意不一致的状态。这会在以后神秘地崩溃你的程序。
  • 锁将被释放。中止线程可能会导致永久保持锁定,导致死锁,等等。

在情况下,我没有说清楚:它是疯狂危险中止线程,你应该只有这样做,当所有的选择更糟。

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

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

如果你确实需要启动一个线程,那么启动这个线程使得主线程和工作线程可以干净而安全地进行通信。“我希望你在这个时候干净地关闭自己”。

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


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

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++;     
         } 
        }  
    } 
    

    }