2015-08-19 35 views
6

Tôi có một đối tượng có chứa một chuỗi hoạt động. Tôi muốn giết thread khi đối tượng nằm ngoài phạm vi.Làm thế nào để chặn hoàn toàn một sợi trong một đối tượng trong C#

using System.IO; 
using System; 
using System.Threading; 

namespace tt { 
    class Program 
    { 
     static void Main() 
     { 
      AnotherClass a = new AnotherClass(); 
      a.Say(); 
     } 

    } 

    class AnotherClass:IDisposable { 
     private bool m_Disposed; 
     private readonly AutoResetEvent m_ResetEvent = new AutoResetEvent(false); 

     public AnotherClass() { 
      Thread t = new Thread(wait); 
      t.Start(); 
     } 

     public void Dispose() { 
      Dispose(true); 
     } 
     private void Dispose(bool disposing) { 
      if (m_Disposed) { 
       return; 
      } 

      if (disposing) { 
       Console.WriteLine("inner disposing"); 
      } 
      m_ResetEvent.Set(); 
      Console.WriteLine("Outer disposing"); 
      m_Disposed = true; 
     } 

     private void wait() { 
      m_ResetEvent.WaitOne(); 
     } 

     ~AnotherClass() { 
      Dispose(false); 
     } 

     public void Say() { 
      Console.WriteLine("HellO"); 
     } 
    } 
} 

Chương trình sẽ chỉ treo trong đó vì không được gọi hàm hủy của AnotherClass. Tôi biết tôi có thể gọi a.Dispose() để giết các chủ đề. Nhưng có cách nào để ngầm giết chủ đề khi đối tượng ra khỏi phạm vi không?

+0

tôi nghĩ cách duy nhất để ngầm chặn luồng là ngắt kết nối nguồn. –

Trả lời

6

Không, điều đó là không thể. Không có tính tham chiếu có thể nhận thấy rằng đối tượng không có tham chiếu nhiều hơn, do đó không có cách nào để làm bất cứ điều gì khi điều đó xảy ra.

Giao diện IDisposable được sử dụng cho các lớp học cần làm gì đó khi một cá thể không được sử dụng nữa và gọi phương thức Dispose là cách bạn báo hiệu bạn đã làm với cá thể.

Cách thông thường để đảm bảo rằng một đối tượng được xử lý khi bạn rời khỏi một phạm vi là để bọc các mã trong một khối using:

static void Main() 
{ 
    using (AnotherClass a = new AnotherClass()) 
    { 
    a.Say(); 
    } 
} 

Khối using là cú pháp đường cho một khối try...finally:

static void Main() 
{ 
    AnotherClass a = new AnotherClass(); 
    try 
    { 
    a.Say(); 
    } 
    finally 
    { 
    if (a != null) 
    { 
     ((Idisposable)a).Dispose(); 
    } 
    } 
} 
+0

Các vị thần và các loài cá nhỏ, tôi yêu 'sử dụng'. Nhớ gọi 'Vứt bỏ' không phải là bất kỳ rắc rối nào, nhưng 'sử dụng' trông có vẻ rất thô lỗ trong mã. –

+0

vì vậy nếu AnotherClass là một thư viện, không có cách nào để đảm bảo rằng người dùng đóng/loại bỏ AnotherClass đúng cách? –

+0

@MonsterHunter Nếu nó thực hiện IDisposable thì có. Nếu bạn không có quyền truy cập vào các logic trong lớp khác và CNTT không vứt bỏ đúng cách, sau đó bạn có thể nhìn vào một thư viện. – Cory

1

Bạn có thể sử dụng xử lý ngoại lệ và sử dụng lỗi được hiển thị dưới dạng ngoại lệ trong khối catch

2

Thêm vào câu trả lời Guffa, tôi nghĩ rằng nó cũng quan trọng cần lưu ý rằng ngay cả khi bạn đã có một cách để phát hiện thời điểm chính xác mà ví dụ AnotherClass của bạn đã vượt quá phạm vi, trong trường hợp này, nó sẽ không bao giờ xảy ra. Và đó là lý do tại sao bạn nhận thấy rằng destructor của bạn không bao giờ được gọi.

Lý do cho điều đó là khi bạn tạo và bắt đầu chuỗi làm việc của mình, luồng được chuyển qua tham chiếu ủy nhiệm trỏ đến phương thức thể hiện wait() có tham chiếu ngầm đến this (ví dụ AnotherClass). Vì vậy, miễn là thread của bạn không tự thoát khỏi phạm vi, nó sẽ giữ một tham chiếu mạnh mẽ đến cá thể AnotherClass và ngăn không cho nó thu gom rác.

+0

Sau đó, làm cách nào để đảm bảo rằng AntherClass sẽ không khiến chương trình bị treo mà không cần chạm vào mã trong Lớp Chương trình? –

+1

Dựa trên thông tin có sẵn, sử dụng mẫu 'IDisposable' theo gợi ý của Guffa là cách tốt nhất để đi. Nhưng bạn cũng đúng trong đó nếu người gọi không gọi là 'Dispose() ', thì nó sẽ không hoạt động. Có một số giải pháp liên quan đến việc sử dụng trình hoàn thiện, nhưng các tùy chọn đó hiếm khi là ý tưởng hay và có thể dẫn đến các vấn đề nghiêm trọng khác. Nếu tôi ở trong đôi giày của bạn, tôi sẽ xem xét việc thay đổi thiết kế lớp học của tôi. Nhưng mà không biết yêu cầu kinh doanh của bạn là gì, thật khó để đề xuất một giải pháp thay thế thiết kế tốt hơn. – sstan

1

Nếu chủ đề của bạn tồn tại với mục đích phục vụ đối tượng vì lợi ích của các chủ đề khác, bạn phải có đối tượng trình bao bọc công khai mà tất cả các chuỗi "quan tâm" trong dịch vụ sẽ chứa tham chiếu mạnh mẽ và bản thân dịch vụ sẽ giữ một tham chiếu dài yếu. Đối tượng bao bọc đó không được giữ bất kỳ thông tin nào mà dịch vụ cần đọc hoặc thao tác, nhưng thay vào đó, hãy chuyển tiếp tất cả các yêu cầu thông tin tới một đối tượng mà cả trình bao bọc và dịch vụ đều giữ các tham chiếu mạnh.

Khi luồng máy chủ đang hoạt động, nó sẽ định kỳ kiểm tra xem tham chiếu yếu với đối tượng bao bọc có còn hoạt động hay không. Nếu không, chủ đề máy chủ sẽ tắt theo cách có trật tự. Lưu ý rằng máy chủ không bao giờ sử dụng một tham chiếu mạnh mẽ đến đối tượng bao bọc - ngay cả tạm thời - vì vậy đối tượng bao bọc sẽ bay hơi ngay khi không ai quan tâm đến nó.

Nếu chuỗi máy chủ có thể bị chặn vô thời gian chờ đợi nhiều thứ khác nhau xảy ra, trình bao bọc phải giữ tham chiếu duy nhất ở bất kỳ đâu trong vũ trụ đến đối tượng cuối cùng có tham chiếu mạnh đến đối tượng máy chủ; khi finalizer bắn, nó nên kiểm tra xem tham chiếu yếu dài có được giữ bởi đối tượng máy chủ vẫn hợp lệ hay không. Nếu không, bạn nên cố gắng di chuyển luồng máy chủ (ví dụ:sử dụng Monitor.TryEnter/Monitor.Pulse. Nếu đối tượng bao bọc vẫn còn sống (finalizers đôi khi có thể giả kích hoạt trong một số kịch bản phục sinh) hoặc finalizer không thể di chuyển thread server, đối tượng finalizable có thể đăng ký lại để hoàn thành.

Sử dụng đối tượng finalizer sẽ làm phức tạp mọi thứ; nếu chuỗi máy chủ có thể tự đánh thức định kỳ mà không cần phải được đẩy nhẹ, điều đó sẽ đơn giản hóa thiết kế. Một finalizer được sử dụng như mô tả, tuy nhiên, nên tương đối mạnh mẽ ngay cả trong các kịch bản liên quan đến sự phục sinh không tự nguyện.

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