2013-02-11 149 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++;     
         } 
        }  
    } 
    

    }