开发者

Waiting for an async method to end in C#

开发者 https://www.devze.com 2023-02-20 13:30 出处:网络
Sample code: class Program { static readonly o开发者_运维知识库bject locker = new object(); static void Main(string[] args)

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消