简体   繁体   中英

How to block an operation until a condition is met?

I am running this code and it is using a fair amount of CPU even though it is doing absolutely nothing most of the time.

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

What is the best way to block until a condition is met?

Use a WaitHandle .

WaitHandle waitHandle = new AutoResetEvent();

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

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

You could also consider changing the interface of your class to raise an event when there is new data to be read. Then you can put your code inside the event handler.

Assuming you are using .NET 4, I'd suggest switching RecievedMessageBuffer to be a BlockingCollection . When you are putting messages into it, call it's Add method. When you want to retrieve a message, call it's Take or TryTake methods. Take will block the reading thread until a message is available, without burning CPU like your original example.

// 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);
    }
}

Above lines of code and specifically AutoResetEvent is available in version 3.5. So simple code like above with some minor correction is very effective because it works and close to foundation API. The correction should be

AutoResetEvent waitHandle = new AutoResetEvent(false); Constructor with argument false makes WaitOne() to wait because AutoResetEven is not reset (false). There is not much advantage of using interface WaitHandle, so I would just use AutoResetEvent instead as it exposes method Set and WaitOne is quite verbose in this case. Most importantly, the constructor argument and should be false.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM