How to block until an asynchronous call is complete?
I have a method which calls an asynchronous method, and a callback which is fired when the asynchronous method finishes.
I want my method to appear syncrhonous, so I've created an AutoResetEvent, called the asyncrhonous method,开发者_StackOverflow the call WaitOne() on the AutoResetEvent instance, and I call Set() in the callback method. Something like this (simplified for this example):
private System.Threading.AutoResetEvent waitRun_m;
public void RunSynchronous()
{
waitRun_m = new System.Threading.AutoResetEvent(false);
CallAsynchronousMethod();
waitRun_m.WaitOne();
}
private void Callback()
{
waitRun_m.Set();
}
Now, is it possible for the call to CallAsynchronousMethod to complete before WaitOne() to be called - causing Set() to be called before WaitOne(). Is there a better way to do this, to avoid this potential issue?
I believe this will answer your question:
Calling Set signals AutoResetEvent to release a waiting thread. AutoResetEvent remains signaled until a single waiting thread is released, and then automatically returns to the non-signaled state. If no threads are waiting, the state remains signaled indefinitely.
You have to be careful, though, because now RunSynchronous doesn't look thread safe. If two different threads call it in an overlapping manner, all hell could break loose.
It is not an issue, the event getting Set before you WaitOne is fully supported. AutoResetEvent would be quite unusable if this wasn't the case.
As Daniel and nobugz said using AutoResetEvent
might be dangerous. You might be calling
waitRun_m.Set();
before you call waitRun_m.WaitOne();
when an async operation is very short. I'd prefer something like this. That way you are sure that you will first enter the wait state, and then call the Pulse
method. Plus you don't have to Close
the AutoResetEvent
which is often forgoten.
private readonly object m_lock = new object();
public void RunSynchronous()
{
lock(m_lock) {
CallAsynchronousMethod();
Monitor.Wait(m_lock);
}
}
private void Callback()
{
lock(m_lock)
Monitor.Pulse(m_lock);
}
精彩评论