Waiting for an async method to end in C#
Sample code:
class Program
{
static readonly o开发者_运维知识库bject locker = new object();
static void Main(string[] args)
{
Func();
Func();
Thread.Sleep(6000);
}
static void Func()
{
Monitor.Enter(locker);
Action act = () =>
{
Thread.Sleep(2000);
};
act.BeginInvoke(a =>
{
Console.WriteLine("exiting..");
Monitor.Exit(locker);
}, null);
Console.WriteLine("Func done...");
}
}
Ideally the console would print out:
Func done...
exiting...
Func done...
exitting...
But, I'm getting:
Func done...
Func done...
exitting...
and then Monitor.Exit throws the exception
Object synchronization method was called from an unsynchronized block of code.
What is the error here? What's the preferred way to achieve this?
Monitor.Enter
and Monitor.Exit
calls have to be made on the same thread. In your sample you call Monitor.Enter
on the UI thread and Monitor.Exit
on a thread created for the asynchronous invocation triggered by BeginInvoke
.
If you want to wait for the async operation to be finished within Func
you could do it like this:
class Program
{
static void Main(string[] args)
{
Func();
Func();
Thread.Sleep(6000);
}
static void Func()
{
Action act = () =>
{
Thread.Sleep(2000);
};
IAsyncResult actAsyncResult = act.BeginInvoke(a =>
{
Console.WriteLine("exiting..");
}, null);
Console.WriteLine("Func done...");
act.EndInvoke(actAsyncResult);
}
}
Nevertheless in your scenario you could then just invoke the delegate synchronously.
Monitor.Enter(locker) is on the current thread, Monitor.Exit is on a different thread as it is invoked from your current thread.
Thus you need to use Monitor.Wait and Monitor.Pulse as well, but ManualResetEvents are easier in your case.
I think you can wait for an event to complete by using ManualResetEvent class. Sorry I don't have any experience with Monitor. But I am using the ManualResetEvent / AutoResetEvent classes for testing callbacks.
Thread shudn't close Monitor
Monitor.Exit(locker);
this is a problem
This error is very misleading. It really doesn't mean what it looks like it means. It actually means that Monitor.Exit
is called before you called Monitor.Enter
on a sync object.
Your Monitor.Exit
call happens on a different thread from the Monitor.Enter
call -- the two don't see each other's sync objects.
精彩评论