2012-06-11 25 views
6

Tôi đang chạy mã này và nó đang sử dụng một số lượng hợp lý của CPU mặc dù nó đang làm hoàn toàn không có gì hầu hết thời gian.Làm thế nào để chặn một hoạt động cho đến khi một điều kiện được đáp ứng?

while (this.IsListening) 
{ 
    while (this.RecievedMessageBuffer.Count > 0) 
    { 
     lock (this.RecievedMessageBuffer) 
     { 
      this.RecievedMessageBuffer[0].Reconstruct(); 
      this.RecievedMessageBuffer[0].HandleMessage(messageHandler); 
      this.RecievedMessageBuffer.RemoveAt(0); 
     } 
    } 
} 

Cách tốt nhất để chặn cho đến khi đáp ứng điều kiện là gì?

+4

'Thread.Sleep()'? –

+0

Thread.Sleep() cũng chặn giao diện người dùng. –

+4

@RanhiruCooray no, đó hầu như luôn là câu trả lời * sai *. Có những cấu trúc dành riêng cho công việc này, như WaitHandle do Mark đề xuất. Xem http://stackoverflow.com/questions/9417260/when-is-it-sensible-to-use-thread-sleep –

Trả lời

7

Giả sử bạn đang sử dụng .NET 4, tôi khuyên bạn nên chuyển đổi RecievedMessageBuffer thành BlockingCollection. Khi bạn đang đặt tin nhắn vào đó, hãy gọi phương thức đó là Add. Khi bạn muốn truy xuất thư, hãy gọi đó là các phương thức Take hoặc TryTake. Take sẽ chặn thread đọc cho đến khi một tin nhắn có sẵn, mà không cần đốt CPU như ví dụ ban đầu của bạn.

// Somewhere else 
BlockingCollection<SomethingLikeAMessage> RecievedMessageBuffer = new BlockingCollection<SomethingLikeAMessage>(); 


// Something like this where your example was 
while (this.IsListening) 
{ 
    SomethingLikeAMessage message; 
    if (RecievedMessageBuffer.TryTake(out message, 5000); 
    { 
     message.Reconstruct(); 
     message.HandleMessage(messageHandler); 
    } 
} 
+1

Cảm ơn rất nhiều! đó là hoàn hảo cho những gì tôi cần! Tôi đã sử dụng SyncronizedCollection <> trước đây nhưng như BlockingCollection <> cũng là thread an toàn, điều này là hoàn hảo cho những gì tôi đang làm! Tất cả mọi thứ đang chạy tuyệt vời trơn tru ngay bây giờ! – MJLaukala

9

Sử dụng WaitHandle.

WaitHandle waitHandle = new AutoResetEvent(); 

// In your thread. 
waitHandle.WaitOne(); 

// In another thread signal that the condition is met. 
waitHandle.Set(); 

Bạn cũng có thể xem xét thay đổi giao diện của lớp học để tăng sự kiện khi có dữ liệu mới được đọc. Sau đó, bạn có thể đặt mã của bạn bên trong trình xử lý sự kiện.

+0

Tôi sẽ phải làm một số thử nghiệm với WaitHandles. Không bao giờ biết về chúng trước ngày hôm nay. Không bao giờ làm bất cứ điều gì quá nghiêm trọng với đa luồng trước một vài tuần trước. – MJLaukala

+0

Tôi không thể sử dụng 'WaitHandle' với phương thức' Set() '. Tôi nghĩ ít nhất phải có 'EventWaitHandle'. – Gucu112

2

Dòng mã và đặc biệt AutoResetEvent có sẵn trong phiên bản 3.5. Vì vậy, mã đơn giản như trên với một số sửa chữa nhỏ là rất hiệu quả bởi vì nó hoạt động và gần với API nền tảng. Chỉnh sửa phải là

AutoResetEvent waitHandle = new AutoResetEvent (false); Constructor với đối số false làm WaitOne() chờ vì AutoResetEven không được đặt lại (false). Không có nhiều lợi thế của việc sử dụng giao diện WaitHandle, vì vậy tôi sẽ chỉ sử dụng AutoResetEvent thay vì nó cho thấy phương thức Set và WaitOne khá tiết trong trường hợp này. Quan trọng nhất, đối số hàm tạo và phải là false.