C# 等待异步方法以C结尾#

C# 等待异步方法以C结尾#,c#,multithreading,thread-safety,monitor,C#,Multithreading,Thread Safety,Monitor,示例代码: class Program { static readonly object locker = new object(); static void Main(string[] args) { Func(); Func(); Thread.Sleep(6000); } static void Func() { Monitor.Enter(locker);

示例代码:

    class Program
{
    static readonly object 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...");
    }
}
理想情况下,控制台会打印出:

Func done...
exiting...
Func done...
exitting...
但是,我得到了:

Func done...
Func done...
exitting...
然后Monitor.Exit抛出异常

从未同步的代码块调用了对象同步方法


这里的错误是什么?实现这一点的首选方法是什么?

我认为您可以使用等待事件完成。对不起,我对显示器没有任何经验。但是我正在使用ManualResetEvent/AutoResetEvent类来测试回调。

我认为您可以使用来等待事件完成。对不起,我对显示器没有任何经验。但是我使用ManualResetEvent/AutoResetEvent类来测试回调。

线程不能关闭监视器

Monitor.Exit(locker);

这是一个问题,线程不能关闭监视器

Monitor.Exit(locker);

这是一个问题

监视器。输入
监视器。必须在同一线程上进行退出
调用。在示例中,您可以调用
Monitor。在UI线程上输入
,然后在为
BeginInvoke
触发的异步调用创建的线程上退出

如果要等待异步操作在
Func
中完成,可以这样做:

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

然而,在您的场景中,您可以同步调用委托。

Monitor.Enter
Monitor.Exit
调用必须在同一线程上进行。在示例中,您可以调用
Monitor。在UI线程上输入
,然后在为
BeginInvoke
触发的异步调用创建的线程上退出

如果要等待异步操作在
Func
中完成,可以这样做:

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);
    }
}
然而,在您的场景中,您可以同步调用委托。

Monitor.Enter(locker)位于当前线程上,Monitor.Exit位于从当前线程调用的不同线程上。
因此,您还需要使用Monitor.Wait和Monitor.Pulse,但手动重置事件在您的情况下更容易。

Monitor.Enter(locker)在当前线程上,Monitor.Exit在从当前线程调用时在不同的线程上。

因此,您还需要使用Monitor.Wait和Monitor.Pulse,但手动重置事件在您的情况下更容易发生。

此错误非常容易误导。它实际上并不意味着它看起来意味着什么。实际上,这意味着在对同步对象调用
Monitor.Enter
之前,会调用
Monitor.Exit


您的
监视器.Exit
调用发生在与
监视器不同的线程上。Enter
调用--这两个调用看不到对方的同步对象。

此错误非常容易引起误解。它实际上并不意味着它看起来意味着什么。实际上,这意味着在对同步对象调用
Monitor.Enter
之前,会调用
Monitor.Exit


您的
监视器.Exit
调用发生在与
监视器不同的线程上。Enter
调用--这两个线程看不到彼此的同步对象。

如果您想在继续之前等待它完成,为什么要执行异步?代码可能不能代表实际问题:)从Main方法调用它的方式不正确它在现实生活中的使用方式。如果你想在继续之前等待它完成,为什么要执行异步?代码可能无法代表实际问题:)从主方法调用它的方式与现实生活中使用它的方式不同。