2010-08-06 32 views
5

Tôi đang viết một dịch vụ cửa sổ sử dụng ThreadPool.QueueUserWorkItem(). Mỗi luồng là một tác vụ ngắn ngủi.Làm cách nào để hoàn thành ThreadPool.Join?

Khi dịch vụ bị dừng, tôi cần đảm bảo rằng tất cả các chuỗi hiện đang thực hiện hoàn tất. Có cách nào chờ đợi cho đến khi hàng đợi tự xóa không?

Trả lời

8

Bạn có thể tạo sự kiện (ví dụ: ManualResetEvent) trong mỗi chuỗi và giữ nó trong danh sách được đồng bộ hóa (sử dụng cấu trúc lock). Đặt sự kiện hoặc xóa sự kiện khỏi danh sách khi tác vụ hoàn tất.

Khi bạn muốn tham gia, bạn có thể sử dụng WaitHandle.WaitAll (MSDN documentation) để chờ tất cả các sự kiện được báo hiệu.

Đó là một hack, nhưng tôi không thể thấy làm thế nào để giảm nó để bất cứ điều gì đơn giản!


Chỉnh sửa: ngoài ra, bạn có thể đảm bảo không có sự kiện mới nào được đăng, sau đó đợi một vài giây. Nếu họ thực sự sống ngắn, bạn sẽ không có vấn đề gì. Thậm chí đơn giản hơn, nhưng còn nhiều hơn nữa.

Cuối cùng, nếu chỉ là một khoảng thời gian ngắn, dịch vụ sẽ không thoát cho đến khi tất cả các chuỗi đã chết (trừ khi chúng là chủ đề nền); vì vậy nếu nó là một khoảng thời gian ngắn, người quản lý kiểm soát dịch vụ sẽ không bận tâm một giây hoặc lâu hơn - bạn chỉ có thể để chúng hết hạn - theo kinh nghiệm của tôi.

+0

Chúng phải ngắn ngủi, nhưng đối với trường hợp sử dụng của tôi, tôi cần đảm bảo nhiều hơn "nên hoạt động". Tôi đang nghĩ đến việc sử dụng bộ đếm luồng khóa liên động để theo dõi số lượng chủ đề trong hồ bơi và đợi số đó bằng 0. – recursive

+0

Thực ra, tôi thích đề xuất đầu tiên của bạn tốt hơn bộ đếm. – recursive

3

Mẫu chuẩn để thực hiện việc này là sử dụng bộ đếm chứa số lượng mục công việc đang chờ xử lý và một số ManualResetEvent được báo hiệu khi bộ đếm đạt đến 0. Điều này thường tốt hơn việc sử dụng một WaitHandle cho mỗi mục công việc vì nó không có quy mô rất tốt khi có nhiều mục công việc đồng thời. Ngoài ra, một số phương thức tĩnh WaitHandle chỉ chấp nhận tối đa 64 phiên bản.

// Initialize to 1 because we are going to treat the current thread as 
// a work item as well. This is to avoid a race that could occur when 
// one work item gets queued and completed before the next work item 
// is queued. 
int count = 1; 
var finished = new ManualResetEvent(false); 
try 
{ 
    while (...) 
    { 
    Interlocked.Increment(ref counter); 
    ThreadPool.QueueUserWorkItem( 
     delegate(object state) 
     { 
     try 
     { 
      // Your task goes here. 
     } 
     finally 
     { 
      // Decrement the counter to indicate the work item is done. 
      if (Interlocked.Decrement(ref count) == 0) 
      { 
      finished.Set(); 
      } 
     } 
     }); 
    } 
} 
finally 
{ 
    // Decrement the counter to indicate the queueing thread is done. 
    if (Interlocked.Decrement(ref count) == 0) 
    { 
    finished.Set(); 
    } 
} 
finished.WaitOne(); 
Các vấn đề liên quan