2010-11-15 25 views
5

Trong mã này, khi button1 được nhấp hai lần, nó tạo 2 chuỗi riêng biệt. Trên một cú nhấp chuột, nó tạo ra một chủ đề mới trên heap và lĩnh vực t1 điểm đến các chủ đề mới trên heap. Khi tôi nhấp vào button2, nó sẽ hủy chuỗi cuối cùng (trong đó t1 đề cập đến).Làm cách nào để hủy nhiều chủ đề?

Làm cách nào để hủy bỏ chủ đề khác?

Thread t1; 
ThreadStart ts1; 

private void button1_Click(object sender, EventArgs e) 
{ 
    ts1 = new ThreadStart(myfunc); 
    t1 = new Thread(ts1); 
    t1.Start(); 
} 

private void button2_Click(object sender, EventArgs e) 
{ 
    t1.Abort(); 
} 
+0

Có lý do nào khiến bạn không thể sử dụng BackgroundWorker hoặc cấu trúc tương tự không? Chủ đề sinh sản liên quan đến rất nhiều chi phí, do đó, nó có ý nghĩa để tái sử dụng chúng bất cứ khi nào có thể. –

Trả lời

7

Vâng, câu trả lời OO sẽ là giữ danh sách chủ đề dưới dạng một trường.

private readonly List<Thread> threads = new List<Thread>(); 

Và sau đó thêm chuỗi mới được tạo vào danh sách trong trình xử lý đầu tiên.

var thread = new Thread(myfunc); 
thread.Start(); 
threads.Add(thread); 

Sau đó, bạn có thể lặp qua từng chuỗi trong trình xử lý thứ hai, hủy từng bước trong số đó.

foreach(var thread in threads) 
    thread.Abort(); 

Nhưng tôi nghĩ rằng điều quan trọng nhất ở đây là có hầu như không bao giờ một lý do chính đáng để gọi Thread.Abort.

Từ MSDN page:

Khi một cuộc gọi đề Abort trên chính nó, tác dụng tương tự như ném một ngoại lệ ; ThreadAbortException xảy ra ngay lập tức và kết quả là có thể dự đoán được. Tuy nhiên, nếu một chuỗi cuộc gọi Hủy bỏ trên một chủ đề khác, hãy hủy hủy bỏ ngắt bất kỳ mã nào là đang chạy. Ngoài ra, cũng có khả năng một trình tạo tĩnh có thể bị hủy bỏ. Trong một số ít trường hợp, điều này có thể ngăn chặn trường hợp của lớp đó từ được tạo trong miền ứng dụng đó. Trong .NET Framework phiên bản 1.0 và 1.1, cơ hội có thể hủy trong khi khối cuối cùng là đang chạy, trong trường hợp này là khối cuối cùng là bị hủy.

Các chủ đề mà các cuộc gọi Abort sức mạnh khối nếu chủ đề đó đang được hủy bỏ là trong một khu vực được bảo vệ của mã, chẳng hạn như một khối catch, cuối cùng khối, hoặc hạn chế thực hiện khu vực. Nếu chuỗi gọi Abort giữ khóa mà chủ đề bị hủy bỏ yêu cầu, có thể xảy ra bế tắc.

Bạn sẽ sử dụng một số dạng tín hiệu tốt hơn, chẳng hạn như đặt ManualResetEvent mà mỗi luồng sẽ thăm dò theo khoảng thời gian perioidic. Ngoài ra, bạn có thể sử dụng lớp BackgroundWorker có một số hỗ trợ để hủy tác vụ (gọi CancelAsync trên đó và nhận các chuỗi công nhân để kiểm tra định kỳ CancellationPending). Nếu bạn đang sử dụng .NET 4.0, bạn cũng có thể sử dụng TPL.

+0

Mô tả hay. Nhưng tôi nghĩ rằng "foreach (var thread trong chủ đề)" có thể gây ra ngoại lệ, "khóa" phải được sử dụng ở đây. – acoolaum

+0

@acoolaum: Cảm ơn. Theo như tôi có thể nói, một 'khóa' là không cần thiết ở đây. Cả hai trình xử lý đều chạy trên vòng lặp tin nhắn của biểu mẫu; họ không thể chạy đồng thời trên các chủ đề khác nhau. – Ani

+0

vâng, bạn nói đúng. – acoolaum

1

Tôi muốn giới thiệu bạn hãy nhìn vào việc xây dựng trong nguyên thủy đồng bộ như ManualResetEvent và WaitHandle. Bạn có thể hỏi một chuỗi nếu nó đang chạy hay không bằng cách cố gắng nối chuỗi với Thread.Join. Việc hủy bỏ một chuỗi chỉ nên được thực hiện như một phương sách cuối cùng nếu luồng không phản hồi.

Dưới đây là ví dụ sửa đổi mã của bạn cho biết cách bạn có thể ngăn khởi động lại chuỗi trước khi nó được dừng đúng cách.

public partial class MainForm : Form 
{ 
    private Thread t1; 
    private ThreadStart ts1; 
    private ManualResetEvent t1resetEvent; 

    public MainForm() 
    { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     // Got a thread? 
     if (t1 != null) {     
      if (!t1.Join(0)) { 
       // The thread seems to be running. 
       // You have to stop the thread first. 
       return; 
      } 
     } 

     t1resetEvent = new ManualResetEvent(false); 
     ts1 = new ThreadStart(MyFunc); 
     t1 = new Thread(ts1); 
     t1.Start(); 
    } 

    private void button2_Click(object sender, EventArgs e) 
    { 
     // Got a thread? 
     if (t1 != null) 
     { 
      // Set the reset event so the thread 
      // knows it's time to stop. 
      t1resetEvent.Set(); 

      // Give the thread four seconds to stop. 
      if (!t1.Join(4000)) { 
       // It did not stop, so abort it. 
       t1.Abort(); 
      } 
     } 
    } 

    private void MyFunc() 
    { 
     // Long running operation... 
     while (true) 
     { 
      // Do someone want us to exit? 
      if (t1resetEvent.WaitOne(0)) { 
       return; 
      }     
     } 
    } 
} 
+0

Một vấn đề với nó là nó sẽ chặn giao diện người dùng cho đến khi nó có thể tham gia t1 –

1

Những người khác đã đưa ra các phiên bản dài của câu trả lời, tuy nhiên giải pháp đơn giản rõ ràng là chỉ đơn giản là bỏ qua tái tạo lại đối tượng thread:

public partial class Form1 : Form 
{ 
    Thread thread1; 
    ThreadStart threadStart1; 

    public Form1() 
    { 
     InitializeComponent(); 

     threadStart1 = new ThreadStart(threadTarget); 
     thread1 = new Thread(threadStart1); 
     thread1.Name = "Button1 thread";  
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     thread1.Start(); 
    } 

    private void button2_Click(object sender, EventArgs e) 
    { 
     thread1.Abort(); 
    } 

    private void threadTarget() 
    { 
     Console.WriteLine(Thread.CurrentThread.Name); 
     for (int i = 0; i < 100; i++) 
     { 
      Console.WriteLine(i); 
      Thread.Sleep(500); 
     } 

    } 
} 

Tuy nhiên, tôi sẽ xem xét cách đọc lên trên Threading trong. NET using one these guides (Tôi muốn giới thiệu Joseph Albahari's guide on aborting - tác giả của C# tóm tắt) thay vì sử dụng phương pháp này, đặc biệt nếu bạn đang thực hiện IO hoặc các hoạt động cơ sở dữ liệu có thể để các đối tượng ở trạng thái không mong muốn.

Các vấn đề liên quan