Chấm dứt luồng C # và Thread.Abort ()


85

Trong MSDN, mô tả của phương thức Thread.Abort () cho biết: "Việc gọi phương thức này thường kết thúc luồng."

Tại sao không LUÔN?

Trong trường hợp nào nó không kết thúc luồng?

Có khả năng nào khác để kết thúc chủ đề không?

Câu trả lời:


60

Thread.Abort()tiêm a ThreadAbortExceptionvào chủ đề. Chủ đề có thể hủy yêu cầu bằng cách gọi điện Thread.ResetAbort(). Ngoài ra, có một số phần mã nhất định, chẳng hạn như finallykhối sẽ thực thi trước khi xử lý ngoại lệ. Nếu vì lý do nào đó mà luồng bị kẹt trong một khối như vậy thì ngoại lệ sẽ không bao giờ được nâng lên trên luồng.

Vì người gọi có rất ít quyền kiểm soát trạng thái của luồng khi gọi Abort(), nên thường không nên làm như vậy. Thay vào đó, hãy chuyển một tin nhắn đến chuỗi yêu cầu chấm dứt.


Loại tin nhắn? Ý bạn là một phương thức gọi?
user101375,

4
Điều đó phụ thuộc vào cách bạn chuyển dữ liệu giữa các chuỗi của bạn. Ví dụ: nếu chuỗi của bạn là một chuỗi công nhân có hàng đợi tác vụ, bạn có thể xếp hàng một thông báo PleaseTermina và để cho chuỗi xử lý nó một cách duyên dáng.
Brian Rasmussen

Chủ đề của tôi có một vấn đề lớn mà cột buồm đã được giải quyết, đó là không có hàng đợi tác vụ.
user101375

Như tôi đã nói, nó phụ thuộc vào cách mã luồng của bạn được thiết kế. Có lẽ bạn có thể báo hiệu thông qua một biến thành viên khi đó. Thật khó để cụ thể hơn nếu không có mã thực tế.
Brian Rasmussen

54

Trong trường hợp nào nó không kết thúc luồng?

Câu hỏi này là một bản sao.

Có gì sai khi sử dụng Thread.Abort ()

Có bất kỳ khả năng nào khác để kết thúc chủ đề không?

Đúng. Vấn đề của bạn là bạn không bao giờ nên bắt đầu một chuỗi mà bạn không thể nói một cách lịch sự để dừng lại, và nó dừng lại kịp thời. Nếu bạn đang ở trong tình huống mà bạn phải bắt đầu một chuỗi có thể (1) khó dừng, (2) lỗi, hoặc tệ nhất là (3) thù địch với người dùng, thì điều cần làm là làm một quy trình mới, bắt đầu tiểu trình trong quy trình mới, rồi kết thúc quy trình khi bạn muốn tiểu trình ngừng hoạt động. Điều duy nhất có thể đảm bảo chấm dứt an toàn luồng bất hợp tác là hệ điều hành gỡ bỏ toàn bộ quy trình của nó.

Xem câu trả lời quá dài của tôi cho câu hỏi này để biết thêm chi tiết:

Sử dụng câu lệnh khóa trong vòng lặp trong C #

Phần có liên quan là phần ở cuối nơi tôi thảo luận về những điều cần cân nhắc liên quan đến việc bạn nên đợi bao lâu để một chuỗi tự kết thúc trước khi bạn hủy bỏ nó.


Eric, làm cách nào để tôi lịch sự yêu cầu một luồng dừng lại nếu luồng đó đang đợi trên một đối tượng đồng bộ hóa, ví dụ: EventWaitHandle.WaitOne () ;?
Corvin

5
@Corvin: hợp đồng giữa hai luồng mô tả cách một luồng giao tiếp với luồng khác tùy thuộc vào tác giả của mã chạy trên các luồng đó. Nếu bạn có các yêu cầu rằng (1) một luồng X phải đợi trên một đối tượng có khả năng là mãi mãi, và (2) luồng Y đó phải có thể ngắt luồng X trong một khoảng thời gian hữu hạn thì tôi nghĩ bạn có các yêu cầu trái ngược nhau; quyết định cái nào thắng. Nếu trước đó, thì luồng Y sẽ phải đợi. Nếu cái sau, thì chuỗi X không nên đợi mãi, nó sẽ đợi một khoảng thời gian nhỏ.
Eric Lippert

Cảm ơn vì đã trả lời. Hãy xem xét kiến ​​trúc sau: Tôi có một ứng dụng phải tự thu nhỏ khi một sự kiện toàn hệ thống nhất định xảy ra. Tôi có một chuỗi trong ứng dụng đó đang đợi một sự kiện được đặt tên chung và thực hiện công việc của nó khi sự kiện đó được thiết lập. Mặt khác, ứng dụng của tôi có thể phải thoát trước khi sự kiện xảy ra, phải đóng chuỗi chờ đó. Cách samurai để viết mã một thứ như vậy là gì?
Corvin

@Corvin: Bạn có thể có một vòng lặp đang đợi (với thời gian chờ ngắn) cho sự kiện, sau đó kiểm tra xem sự kiện có nên dừng việc chờ đợi hay không (để nó có thể thoát bình thường). Bằng cách này, bạn có thể báo hiệu chuỗi của mình rằng nó sẽ dừng lại và bạn chỉ phải đợi đến khi hết thời gian để nó dừng lại.
Kevin Kibler

2
@Corvin, nếu bạn đặt chuỗi chờ đó thành chuỗi nền, thì bạn không cần phải đóng nó trước khi ứng dụng thoát.
Don Kirkby

17

Tại sao không LUÔN? Trong trường hợp nào nó không kết thúc chủ đề?

Đối với người mới bắt đầu, một chuỗi có thể bắt một ThreadAbortExceptionvà hủy bỏ kết thúc của chính nó. Hoặc nó có thể thực hiện một phép tính mất vĩnh viễn trong khi bạn đang cố gắng hủy bỏ nó. Do đó, thời gian chạy không thể đảm bảo rằng luồng sẽ luôn kết thúc sau khi bạn yêu cầu nó.

ThreadAbortException có thêm:

Khi một lệnh gọi đến phương thức Abort để hủy một luồng, thời gian chạy ngôn ngữ chung sẽ ném ra một ThreadAbortException. ThreadAbortException là một ngoại lệ đặc biệt có thể được bắt, nhưng nó sẽ tự động được nâng lên một lần nữa ở cuối khối bắt. Khi ngoại lệ này được nâng lên, thời gian chạy thực thi tất cả các khối cuối cùng trước khi kết thúc luồng. Vì luồng có thể thực hiện tính toán không giới hạn trong các khối cuối cùng hoặc lệnh gọi Thread.ResetAbort()hủy bỏ, không có gì đảm bảo rằng luồng sẽ kết thúc.

Bạn không cần phải Abort()xâu chuỗi thủ công. CLR sẽ thực hiện tất cả công việc khó khăn cho bạn nếu bạn chỉ để phương thức trong luồng trả về; điều đó sẽ kết thúc luồng bình thường.


Tôi cần Abort () nó, vì một vòng lặp thông báo đã bắt đầu trên chuỗi đó (Dispatcher.Run ();). Nếu tôi hiểu đúng, tôi cần Gọi một phương thức gọi return vào chuỗi để kết thúc nó?
user101375

7

FileStream.Read()đến một đường ống được đặt tên hiện không nhận được bất kỳ thứ gì (đọc khối cuộc gọi trong khi chờ dữ liệu đến) sẽ không phản hồi Thread.Abort(). Nó vẫn còn bên trong Read()cuộc gọi.


6

Điều gì sẽ xảy ra nếu một luồng đang giữ khóa và bị hủy / hủy? Nguồn lực vẫn bị kẹt

Nó hoạt động tốt khi một luồng gọi tự hủy bỏ mà không phải bởi luồng khác. Hủy bỏ, buộc chấm dứt chuỗi bị ảnh hưởng ngay cả khi nó chưa hoàn thành nhiệm vụ và không tạo cơ hội cho việc dọn dẹp tài nguyên

tham khảo MSDN


xem: Các phương pháp hay nhất về phân luồng được quản lý


5

Tôi dường như không thể hủy bỏ một chuỗi bị mắc kẹt trong một vòng lặp:

//immortal
Thread th1 = new Thread(() => { while (true) {}});

Tuy nhiên, tôi có thể hủy chuỗi nếu ngủ trong vòng lặp:

//mortal
Thread th2 = new Thread(() => { while (true) { Thread.Sleep(1000); }});

1
điều này có vẻ không đúng, tôi đã chạy một chương trình thử nghiệm: `{var th = new Thread (() => {int i = 0; try {while (true) {i ++;}} catch (Exception e) { Console.WriteLine ("aborting @ {0}", i);}}); th.Start (); Thread.Sleep (1000); th.Abort (); th.Join (); }
Weipeng L


3

Vì bạn có thể bắt ThreadAbortExceptionvà gọi Thread.ResetAbortbên trong trình xử lý.


0

OT: Để biết toàn diện, ngôn ngữ bất khả tri, hữu ích đáng ngờ và hài hước đáng kinh ngạc về đồng thời, hãy xem Verity Stob !


-1

Tôi đã gặp trường hợp luồng quá bận để nghe lệnh gọi Abort (), điều này thường dẫn đến một ThreadAbortingException được ném vào mã của tôi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.