2010-09-23 35 views
6

Tôi đang cố gắng sử dụng ThreadPool.RegisterWaitForSingleObject để thêm bộ hẹn giờ vào một tập hợp chủ đề. Tôi tạo ra 9 chủ đề và đang cố gắng để cung cấp cho mỗi người trong số họ một cơ hội bình đẳng của hoạt động như tại thời điểm này có vẻ là một chút đói xảy ra nếu tôi chỉ cần thêm chúng vào hồ bơi thread. Tôi cũng đang cố gắng triển khai một sự kiện đặt lại thủ công vì tôi muốn tất cả 9 chủ đề thoát ra trước khi tiếp tục.Cách chính xác để thực hiện ThreadPool.RegisterWaitForSingleObject

Cách tốt nhất để đảm bảo rằng mỗi chuỗi trong threadpool có cơ hội bình đẳng khi chạy như hàm mà tôi đang gọi có vòng lặp và dường như mỗi luồng (hoặc bất kỳ cái nào chạy trước) bị kẹt trong đó và những người khác không có cơ hội để chạy.

resetEvents = new ManualResetEvent[table_seats]; 
      //Spawn 9 threads 
      for (int i = 0; i < table_seats; i++) 
      { 
       resetEvents[i] = new ManualResetEvent(false); 
       //AutoResetEvent ev = new AutoResetEvent(false); 
       RegisteredWaitHandle handle = ThreadPool.RegisterWaitForSingleObject(autoEvent, ObserveSeat, (object)i, 100, false); 
      } 

      //wait for threads to exit 
      WaitHandle.WaitAll(resetEvents); 

Tuy nhiên, việc sử dụng resetEvents [] hoặc ev dường như không hoạt động bình thường cũng không thành vấn đề. Tôi có thể thực hiện điều này hay là tôi (có thể) hiểu lầm cách họ nên làm việc.

Xin cảm ơn, R.

Trả lời

4

Tôi sẽ không sử dụng RegisterWaitForSingleObject cho mục đích này. Các mẫu tôi sẽ mô tả ở đây yêu cầu tải xuống Reactive Extensions vì bạn đang sử dụng .NET v3.5.

Trước tiên, để chờ tất cả các mục công việc từ ThreadPool để hoàn tất sử dụng lớp CountdownEvent. Điều này là thanh lịch và có thể mở rộng hơn nhiều so với việc sử dụng nhiều phiên bản ManualResetEvent. Ngoài ra, phương pháp WaitHandle.WaitAll được giới hạn ở 64 tay cầm.

var finished = new CountdownEvent(1); 
for (int i = 0; i < table_seats; i++) 
{ 
    finished.AddCount(); 
    ThreadPool.QueueUserWorkItem(ObserveSeat); 
    (state) => 
    { 
     try 
     { 
     ObserveSeat(state); 
     } 
     finally 
     { 
     finished.Signal(); 
     } 
    }, i); 
} 
finished.Signal(); 
finished.Wait(); 

Thứ hai, bạn có thể thử gọi Thread.Sleep(0) sau nhiều lần lặp của vòng lặp để buộc một chuyển ngữ cảnh để các chủ đề lãi suất hiện hành khác. Nếu bạn muốn có một chiến lược phối hợp phức tạp hơn thì sử dụng lớp Barrier. Thêm một tham số khác vào hàm ObserveSeat của bạn chấp nhận cơ chế đồng bộ hóa này. Bạn có thể cung cấp nó bằng cách chụp nó trong biểu thức lambda trong đoạn mã trên.

public void ObserveSeat(object state, Barrier barrier) 
{ 
    barrier.AddParticipant(); 
    try 
    { 
    for (int i = 0; i < NUM_ITERATIONS; i++) 
    { 
     if (i % AMOUNT == 0) 
     { 
     // Let the other threads know we are done with this phase and wait 
     // for them to catch up. 
     barrier.SignalAndWait(); 
     } 
     // Perform your work here. 
    } 
    } 
    finally 
    { 
    barrier.RemoveParticipant(); 
    } 
} 

Lưu ý rằng mặc dù phương pháp này chắc chắn sẽ ngăn chặn sự cố đói có thể hạn chế thông lượng của chuỗi. Gọi số SignalAndWait quá nhiều có thể gây ra rất nhiều chuyển ngữ cảnh không cần thiết, nhưng gọi nó quá ít có thể gây ra rất nhiều chờ đợi không cần thiết. Bạn có lẽ sẽ phải điều chỉnh AMOUNT để có được sự cân bằng tối ưu của thông lượng và đói. Tôi nghi ngờ có thể có một cách đơn giản để thực hiện việc điều chỉnh động.

+1

Cảm ơn, tôi chưa có thời gian để kiểm tra điều này nhưng cảm ơn Brian vì câu trả lời. – flavour404

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