2012-06-11 2 views
6

Я запускаю этот код, и он использует достаточное количество ЦП, даже если он почти ничего не делает.Как заблокировать операцию до тех пор, пока не будет выполнено условие?

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

Каков наилучший способ блокировки до тех пор, пока не будет выполнено условие?

+4

'Thread.Sleep()'? –

+0

Thread.Sleep() также блокирует пользовательский интерфейс. –

+4

@ RanhiruCooray нет, это почти всегда * неправильный ответ. Есть структуры, посвященные этой работе, такие как WaitHandle, предложенные Марком. См. Http://stackoverflow.com/questions/9417260/when-is-it-sensible-to-use-thread-sleep –

ответ

7

Предполагая, что вы используете .NET 4, я бы предложил переключить RecievedMessageBuffer на BlockingCollection. Когда вы вводите в него сообщения, назовите его Add. Когда вы хотите получить сообщение, вызовите его Take или TryTake методов. Take будет блокировать поток чтения до тех пор, пока сообщение не будет доступно, без записи процессора, как ваш оригинальный пример.

// 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

Большое спасибо! это прекрасно для того, что мне нужно! Я использовал SyncronizedCollection <> раньше, но поскольку BlockingCollection <> также является потокобезопасным, это идеально подходит для того, что я делаю! Теперь все работает фантастически ровно! – MJLaukala

9

Использовать WaitHandle.

WaitHandle waitHandle = new AutoResetEvent(); 

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

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

Вы также можете рассмотреть возможность изменения интерфейса своего класса, чтобы поднять событие, когда есть новые данные для чтения. Затем вы можете поместить свой код внутри обработчика события.

+0

Мне нужно провести некоторое тестирование с WaitHandles. Никогда не знал о них до сегодняшнего дня. Никогда не делал ничего серьезного в многопоточности до нескольких недель назад. – MJLaukala

+0

Я не мог использовать 'WaitHandle' с методом' Set() '. Я думаю, что должно быть хотя бы 'EventWaitHandle'. – Gucu112

2

Выше строк кода и, в частности, AutoResetEvent доступно в версии 3.5. Таким образом, простой код, подобный выше с некоторой незначительной коррекцией, очень эффективен, потому что он работает и приближается к API основания. Коррекция должна быть

AutoResetEvent waitHandle = новый AutoResetEvent (false); Конструктор с аргументом false заставляет WaitOne() ждать, поскольку AutoResetEven не сбрасывается (false). Существует не так много преимуществ использования интерфейса WaitHandle, поэтому я бы просто использовал AutoResetEvent, поскольку он предоставляет метод Set и WaitOne в этом случае довольно многословный. Самое главное, аргумент конструктора и должен быть ложным.