Best Practice: Blocking execution while waiting for an Async method
I am trying to adapt an existing program (internally written) to use a different library than it originally did. I've abstracted most of library-specific code away (seems to be the easier part).
The issue is, the old library would execute a call using a blocking method, and our internal program is expecting a blocking method to be called, but the new library uses an async method.
I was wondering what the best practice would be for waiting for the async operation to complete. My first thought was to have a boolean flag called completed, and spin in a while loop until completed == true.
I should note that this is for a quick proof of concept I'm trying to put together for my stakeholder, and if the stakeholders sign off on the project, I'm going to rewrite the offending part of our program. But for the time being, I need to just wait for the开发者_如何学编程 block the function calling the async method until the async call is complete
Instead of a flag, I'd think you'd want to use something like a mutex.
In order to do this, that library needs to have an event to notify you once your async call is done. It would look like this:
- Create your mutex
- In your async complete method, add in 'myMutex.Release();"
- In your main method, after you call the async method, add in "myMutex.WaitOne();". This will block the thread until your async call is complete.
It's been a while since I've used this stuff, but I'm pretty sure that's how it should work.
edit: Oops, I think I was thinking of a semaphore, not mutex:
private static Semaphore mySemaphore = new Semaphore(0, 1);
static void Main(string[] args)
{
Console.WriteLine("Waiting on async call");
(new Thread(ASyncCallCompleted)).Start();
mySemaphore.WaitOne();
Console.WriteLine("Waiting Completed");
}
private static void ASyncCallCompleted()
{
Thread.Sleep(5000);
mySemaphore.Release();
}
edit #2: Per Thorarin's suggestion; it sounds like this class was designed to handle situations like this in .Net:
private static AutoResetEvent mySync = new AutoResetEvent(false);
static void Main(string[] args)
{
Console.WriteLine("Waiting on async call");
(new Thread(ASyncCallCompleted)).Start();
mySync.WaitOne();
Console.WriteLine("Waiting Completed");
Console.Read();
}
private static void ASyncCallCompleted()
{
Thread.Sleep(5000);
mySync.Set();
}
Pass a countdown latch to the async method, and wait on the latch. When the async method is complete, it will notify you on the countdown latch, and execution can continue. A monitor could in principal also be used, but is unsafe in the unfortunate case that the async method completes before you can call wait, and you therefore miss the notify.
Oh, and in the .NET world, a countdown latch is called a CountdownEvent: CountdownEvent Class
This should work for at most one simultaneous call to BlockingCall
. Otherwise you will need separate AutoResetEvent
instances to determine which call has finished. Anyway:
delegate void Callback();
class BlockAsync
{
AutoResetEvent _waitHandle = new AutoResetEvent(false);
public void BlockingCall()
{
AsyncCall(AsyncCallCompleted);
_waitHandle.WaitOne();
}
void AsyncCall(Callback callback)
{
// Example is not actually asynchronous, to demonstrate the solution
// is free of race conditions.
callback();
}
void AsyncCallCompleted()
{
_waitHandle.Set();
}
}
精彩评论