首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何异步处理?

如何异步处理?
EN

Stack Overflow用户
提问于 2008-12-30 12:14:26
回答 9查看 22.5K关注 0票数 24

假设我有一个实现IDisposable接口的类。如下所示:

MyClass使用一些非托管资源,因此IDisposable中的Dispose()方法会释放这些资源。MyClass应按如下方式使用:

代码语言:javascript
复制
using ( MyClass myClass = new MyClass() ) {
    myClass.DoSomething();
}

现在,我想实现一个异步调用DoSomething()的方法。我在MyClass中添加了一个新方法

现在,在客户端,应该像这样使用MyClass

代码语言:javascript
复制
using ( MyClass myClass = new MyClass() ) {
    myClass.AsyncDoSomething();
}

但是,如果我不做任何其他事情,这可能会失败,因为对象myClass可能会在调用DoSomething()之前被释放(并抛出意外的ObjectDisposedException).因此,应该延迟对Dispose()方法的调用(隐式或显式),直到完成对DoSomething()的异步调用。

我认为Dispose()方法中的代码应该以异步方式执行,并且只有在所有异步调用都被解析为之后才能执行。我想知道实现这个目标的最好方法是什么。

谢谢。

注意:为了简单起见,我没有详细介绍Dispose()方法是如何实现的。在现实生活中,我通常遵循Dispose模式(http://msdn.microsoft.com/en-us/library/fs2xkftw(VS.80%29.aspx)

更新:非常感谢您的回复。我很感谢你的努力。作为chakrit has commented,我需要对异步DoSomething的多个调用可以进行。理想情况下,这样的代码应该可以正常工作:

代码语言:javascript
复制
using ( MyClass myClass = new MyClass() ) {

    myClass.AsyncDoSomething();
    myClass.AsyncDoSomething();

}

我将研究计数信号量,这似乎就是我要找的。这也可能是一个设计问题。如果方便的话,我将与您分享一些真实案例以及MyClass的真正用途。

EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2008-12-30 12:46:48

因此,我的想法是保留等待完成的AsyncDoSomething()的数量,并仅在此计数达到零时进行处理。我最初的方法是:

代码语言:javascript
复制
public class MyClass : IDisposable {

    private delegate void AsyncDoSomethingCaller();
    private delegate void AsyncDoDisposeCaller();

    private int pendingTasks = 0;

    public DoSomething() {
        // Do whatever.
    }

    public AsyncDoSomething() {
        pendingTasks++;
        AsyncDoSomethingCaller caller = new AsyncDoSomethingCaller();
        caller.BeginInvoke( new AsyncCallback( EndDoSomethingCallback ), caller);
    }

    public Dispose() {
        AsyncDoDisposeCaller caller = new AsyncDoDisposeCaller();
        caller.BeginInvoke( new AsyncCallback( EndDoDisposeCallback ), caller);
    }

    private DoDispose() {
        WaitForPendingTasks();

        // Finally, dispose whatever managed and unmanaged resources.
    }

    private void WaitForPendingTasks() {
        while ( true ) {
            // Check if there is a pending task.
            if ( pendingTasks == 0 ) {
                return;
            }

            // Allow other threads to execute.
            Thread.Sleep( 0 );
        }
    }

    private void EndDoSomethingCallback( IAsyncResult ar ) {
        AsyncDoSomethingCaller caller = (AsyncDoSomethingCaller) ar.AsyncState;
        caller.EndInvoke( ar );
        pendingTasks--;
    }

    private void EndDoDisposeCallback( IAsyncResult ar ) {
        AsyncDoDisposeCaller caller = (AsyncDoDisposeCaller) ar.AsyncState;
        caller.EndInvoke( ar );
    }
}

如果两个或更多线程尝试并发读/写pendingTasks变量,则可能会出现一些问题,因此应使用lock关键字来防止竞争条件:

代码语言:javascript
复制
public class MyClass : IDisposable {

    private delegate void AsyncDoSomethingCaller();
    private delegate void AsyncDoDisposeCaller();

    private int pendingTasks = 0;
    private readonly object lockObj = new object();

    public DoSomething() {
        // Do whatever.
    }

    public AsyncDoSomething() {
        lock ( lockObj ) {
            pendingTasks++;
            AsyncDoSomethingCaller caller = new AsyncDoSomethingCaller();
            caller.BeginInvoke( new AsyncCallback( EndDoSomethingCallback ), caller);
        }
    }

    public Dispose() {
        AsyncDoDisposeCaller caller = new AsyncDoDisposeCaller();
        caller.BeginInvoke( new AsyncCallback( EndDoDisposeCallback ), caller);
    }

    private DoDispose() {
        WaitForPendingTasks();

        // Finally, dispose whatever managed and unmanaged resources.
    }

    private void WaitForPendingTasks() {
        while ( true ) {
            // Check if there is a pending task.
            lock ( lockObj ) {
                if ( pendingTasks == 0 ) {
                    return;
                }
            }

            // Allow other threads to execute.
            Thread.Sleep( 0 );
        }
    }

    private void EndDoSomethingCallback( IAsyncResult ar ) {
        lock ( lockObj ) {
            AsyncDoSomethingCaller caller = (AsyncDoSomethingCaller) ar.AsyncState;
            caller.EndInvoke( ar );
            pendingTasks--;
        }
    }

    private void EndDoDisposeCallback( IAsyncResult ar ) {
        AsyncDoDisposeCaller caller = (AsyncDoDisposeCaller) ar.AsyncState;
        caller.EndInvoke( ar );
    }
}

我看到了这种方法的问题。由于资源的释放是异步完成的,因此类似这样的操作可能会起作用:

代码语言:javascript
复制
MyClass myClass;

using ( myClass = new MyClass() ) {
    myClass.AsyncDoSomething();
}

myClass.DoSomething();

当预期的行为应该是在使用子句的外部调用DoSomething()时启动ObjectDisposedException。但我觉得这还不够糟糕,不足以重新考虑这个解决方案。

票数 1
EN

Stack Overflow用户

发布于 2008-12-30 12:28:44

看起来您使用的是基于事件的异步模式(see here for more info about .NET async patterns),因此通常在类上有一个事件,该事件在异步操作完成时触发,名为DoSomethingCompleted (请注意,AsyncDoSomething实际上应该被称为DoSomethingAsync才能正确遵循该模式)。公开此事件后,您可以编写以下代码:

代码语言:javascript
复制
var myClass = new MyClass();
myClass.DoSomethingCompleted += (sender, e) => myClass.Dispose();
myClass.DoSomethingAsync();

另一种选择是使用dispose模式,您可以将调用dispose方法的委托传递给AsyncCallback参数(关于此模式的更多信息也在上面的页面中)。在本例中,您将使用BeginDoSomethingEndDoSomething方法而不是DoSomethingAsync,并将其命名为类似于...

代码语言:javascript
复制
var myClass = new MyClass();
myClass.BeginDoSomething(
    asyncResult => {
                       using (myClass)
                       {
                           myClass.EndDoSomething(asyncResult);
                       }
                   },
    null);        

但无论采用哪种方式,都需要一种方式通知调用方异步操作已完成,以便它可以在正确的时间释放对象。

票数 11
EN

Stack Overflow用户

发布于 2008-12-30 12:23:08

异步方法通常有一个回调,允许您在完成后执行一些操作。如果这是您的情况,应该是这样的:

代码语言:javascript
复制
// The async method taks an on-completed callback delegate
myClass.AsyncDoSomething(delegate { myClass.Dispose(); });

另一种方式是异步包装器:

代码语言:javascript
复制
ThreadPool.QueueUserWorkItem(delegate
{
    using(myClass)
    {
        // The class doesn't know about async operations, a helper method does that
        myClass.DoSomething();
    }
});
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/400130

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档