Winforms 最佳实践:在等待异步方法时阻止执行

Winforms 最佳实践:在等待异步方法时阻止执行,winforms,c#-3.0,asynchronous,multithreading,blocking,Winforms,C# 3.0,Asynchronous,Multithreading,Blocking,我正在尝试调整一个现有的程序(内部编写的),以使用与最初不同的库。我已经抽象了大多数特定于库的代码(似乎是最简单的部分) 问题是,旧库将使用阻塞方法执行调用,我们的内部程序希望调用阻塞方法,但新库使用异步方法 我想知道等待异步操作完成的最佳实践是什么。我的第一个想法是使用一个名为completed的布尔标志,并在while循环中旋转,直到completed==true 我应该注意到,这是为了快速证明我试图为我的利益相关者制定的概念,如果利益相关者在项目上签字,我将重写我们计划中有问题的部分。但目

我正在尝试调整一个现有的程序(内部编写的),以使用与最初不同的库。我已经抽象了大多数特定于库的代码(似乎是最简单的部分)

问题是,旧库将使用阻塞方法执行调用,我们的内部程序希望调用阻塞方法,但新库使用异步方法

我想知道等待异步操作完成的最佳实践是什么。我的第一个想法是使用一个名为completed的布尔标志,并在while循环中旋转,直到completed==true


我应该注意到,这是为了快速证明我试图为我的利益相关者制定的概念,如果利益相关者在项目上签字,我将重写我们计划中有问题的部分。但目前,我只需要等待调用异步方法的函数阻塞,直到异步调用完成

将倒计时锁存器传递给异步方法,然后等待锁存器。当异步方法完成时,它将在倒计时锁存器上通知您,并且可以继续执行。原则上也可以使用监视器,但如果异步方法在调用wait之前完成,并且因此错过了notify,那么这种情况是不安全的


哦,在.NET世界中,倒计时闩锁被称为倒计时事件:

我想你应该使用类似于国旗的东西,而不是国旗

为了做到这一点,该库需要有一个事件在异步调用完成后通知您。它看起来是这样的:

  • 创建互斥对象
  • 在异步完成方法中,添加“myMutex.Release();"
  • 在main方法中,在调用异步方法后,添加“myMutex.WaitOne();。这将阻止线程,直到异步调用完成
  • 我已经有一段时间没用过这种东西了,但我很确定它应该是这样工作的

    编辑:哎呀,我想我想到的是一个,而不是互斥体:

        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();
        }
    
    编辑#2:根据Thorarin的建议;听起来这个类是为处理.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();
        }
    

    这最多只能同时调用一次
    BlockingCall
    。否则,您将需要单独的
    AutoResetEvent
    实例来确定哪个调用已完成。无论如何:

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

    除非异步方法很快,并且在waitone之前调用release,否则这将起作用……我稍微更改了答案;我认为如果信号量在waitone之前被释放方法被调用时,它不会阻止
    AutoResetEvent
    信号量
    更有意义。此外,如果您想考虑多线程环境中的多个同时调用,则需要修改此示例。倒计时锁存器和信号量非常相似,但通常用于不同的目的。参见@disown:John提到的种族条件。如果异步调用完成得太快,可能会导致
    信号量异常
    AutoResetEvent
    也可以,因为实际上不需要计算任何值。而且由于
    CountdownEvent
    也仅为.NET4.0版本。。。我很高兴他们加了这个。