문제

자가를 구현하는 클래스 IDisposable 인터페이스입니다.무언가 이것을 좋아한다:

http://www.flickr.com/photos/garthof/3149605015/

MyClass 일부를 사용하는 관리되지 않는 리소스를 따라서, 폐기() 에서 방법 IDisposable 자료 그 리소스입니다. MyClass 해야 다음과 같이 사용:

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

지금,나는 원하는 구현하는 메소드 호출 DoSomething() 비동기적으로 수행됩니다.추가 새로운 방법 MyClass:

http://www.flickr.com/photos/garthof/3149605005/

이제,클라이언트 측에서, MyClass 해야 다음과 같이 사용:

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

그러나면 아무것도 하지 않아요 다른 사람이 실패할 수 있는 개체 myClass 수도 폐기되기 전에 DoSomething() 불(고 예기치 않은 ObjectDisposedException).그래서,전화 폐기() 방법(암시적 또는 명시적으로)연기해야 될 때까지 비동기식 전화기 DoSomething() 이 수행됩니다.

나는 생각에서 코드 폐기() 방법을 실행해야 에서는 비동기식 방법이며,한 번만 모든 비동기화 해결.나는 알고 싶어할 수 있는 가장 좋은 방법이 될 이 작업을 수행할 수 있습니다.

감사합니다.

참고:간단하게 하기 위하여,나를 입력하지 않은 방법의 세부 사항의 처분()메소드는 구현된다.실제 생활에서 나는 일반적으로 따르 폐기 패턴.


업데이트: 당신은 당신의 응답합니다.감사합니다.로 chakrit 댓글을 달았, 가 필요하는 여러 번 호출하는 비동기 DoSomething 만들 수 있습니다.이상적으로,같은 것이 잘 작동합니다:

using ( MyClass myClass = new MyClass() ) {

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

}

나는 공부를 계산 세마포어,그것은 내가 무엇을 찾고 있습니다.그것은 또한 수의 디자인 문제입니다.면 내가 그것을 찾을 편리하게 공유할 것입니다 당신과 함께 몇 가지의 실제 경우 무엇 MyClass 정말하지 않습니다.

도움이 되었습니까?

해결책 6

그래서 내 생각은 얼마나 많은지 유지하는 것입니다 AsyncDosomething () 완료 할 예정이며,이 카운트가 0에 도달 할 때만 처분합니다. 나의 초기 접근법은 다음과 같습니다.

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

둘 이상의 스레드가 읽고 쓰려고하면 일부 문제가 발생할 수 있습니다. 보류 작업 동시에 변수 자물쇠 키워드를 사용하여 인종 조건을 예방해야합니다.

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

이 접근법에 문제가 있습니다. 자원의 해제가 비동기식으로 수행되므로 이와 같은 작업이 효과가있을 수 있습니다.

MyClass myClass;

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

myClass.DoSomething();

예상되는 동작이 시작 해야하는 경우 ObjectDispossionException 언제 dosomething () 외부로 호출됩니다 사용 절. 그러나 나는이 솔루션을 다시 생각할만큼 나쁘지 않습니다.

다른 팁

그것처럼 당신이 사용하는 경우 이벤트 기반으로 비동기 패턴(여기에 참조에 대한 더 많은 정보에 대해입니다.NET async 패턴 다)그래서 무엇이 당신이 일반적으로는 이벤트에서 클래스 발생하는 경우 비동기 작업이 완료되면 이름 DoSomethingCompleted (note AsyncDoSomething 정말라 DoSomethingAsync 패턴을 따라 올바르게).이 이벤트에 노출을 쓸 수 있다:

var myClass = new MyClass();
myClass.DoSomethingCompleted += (sender, e) => myClass.Dispose();
myClass.DoSomethingAsync();

다른 대안은 사용 IAsyncResult 패턴,당신이 통과할 수 있는 대리자를 호출하는 폐기하는 방법 AsyncCallback 매개 변수(에 대한 자세한 정보를 이 페이지에 위도).이 경우에 당신이 BeginDoSomethingEndDoSomething 방법 대신 DoSomethingAsync, 고 부를 것이다 그것은 무언가가 다음과 같...

var myClass = new MyClass();
myClass.BeginDoSomething(
    asyncResult => {
                       using (myClass)
                       {
                           myClass.EndDoSomething(asyncResult);
                       }
                   },
    null);        

하지만 어느 방법으로 당신이 그것,당신은 방법이 필요를 위해 호출자가 통지하는 비동기 작업을 완료할 수 있도록의 처분에 있는 객체에 올바른 시간입니다.

비동기 방법에는 일반적으로 콜백이있어 완료시 약간의 작업을 수행 할 수 있습니다. 이것이 당신의 경우라면 다음과 같은 것입니다.

// The async method taks an on-completed callback delegate
myClass.AsyncDoSomething(delegate { myClass.Dispose(); });

이 주위의 다른 방법은 비동기 래퍼입니다.

ThreadPool.QueueUserWorkItem(delegate
{
    using(myClass)
    {
        // The class doesn't know about async operations, a helper method does that
        myClass.DoSomething();
    }
});

비동기 처분을 허용하기 위해 어떻게 든 코드를 변경하지 않을 것입니다. 대신 AsyncDosomething에 대한 호출이 이루어질 때, 실행하는 데 필요한 모든 데이터의 사본이있을 것입니다. 이 방법은 자원의 경우 모든 것을 정리할 책임이 있어야합니다.

콜백 메커니즘을 추가하고 콜백으로 정리 기능을 전달할 수 있습니다.

var x = new MyClass();

Action cleanup = () => x.Dispose();

x.DoSomethingAsync(/*and then*/cleanup);

그러나 동일한 개체 인스턴스에서 여러 개의 비동기 호출을 실행하려면 문제가 발생합니다.

한 가지 방법은 간단한 것을 구현하는 것입니다 세마포어 계산 이랑 세마포어 수업 실행 된 비동기 작업의 수를 계산합니다.

카운터를 myclass에 추가하고 모든 비동기 호출에 카운터를 증가시켜 출구에서 사전에 사전을 늘리십시오. 세마포어가 0이면 클래스를 배치 할 준비가되었습니다.

var x = new MyClass();

x.DoSomethingAsync();
x.DoSomethingAsync2();

while (x.RunningJobsCount > 0)
    Thread.CurrentThread.Sleep(500);

x.Dispose();

그러나 나는 그것이 이상적인 방법이라고 의심합니다. 디자인 문제 냄새가납니다. 어쩌면 MyClass 디자인을 다시 생각하면 이것을 피할 수 있습니까?

약간의 MyClass 구현을 공유 할 수 있습니까? 무엇을해야합니까?

나는 Microsoft가 IDisposable 구현이 허용 해야하는 계약 Dispose 모든 스레딩 컨텍스트에서 호출되는 경우, 객체의 생성은 그 실링 컨텍스트의 지속적인 존재를 강요 할 수있는 방식이 없기 때문에 그것이 생성 된 스레딩 컨텍스트의 지속적인 존재를 강요 할 수 있기 때문입니다. 객체를 생성하는 스레드가 어떻게 든 개체가 쓸모 없게되고 할 수 있도록 코드를 디자인 할 수 있습니다. Dispose 편리하게, 그리고 스레드가 더 이상 다른 것에 필요하지 않으면 모든 적절한 개체가 될 때까지 DisposeD, 그러나 나는 스레드 부분에 특별한 행동이 필요하지 않은 표준 메커니즘이 있다고 생각하지 않습니다. Dispose.

가장 좋은 방법은 아마도 공통 스레드 (아마도 UI 스레드) 내에 관심있는 모든 관심 객체를 만들고, 스레드가 관심있는 대상의 수명 동안 머무를 것을 보장하고, 같은 것을 사용하는 것입니다. Control.BeginInvoke 개체의 처분을 요청합니다. 단, 객체 생성이나 정리도 오랜 시간 동안 차단되지 않으면 좋은 접근 방식 일 수 있지만, 어느 작업 중 하나가 다른 접근 방식을 차단할 수 있다면 다른 접근 방식이 필요할 수 있습니다 [아마도 자체 스레드로 숨겨진 더미 형태를 열어서 가능합니다. 사용 Control.BeginInvoke 거기].

또는, 당신이 통제 할 수있는 경우 IDisposable 구현, 안전하게 비동기식으로 해고 될 수 있도록 설계하십시오. 많은 경우에, 아무도 항목이 배치 될 때 항목을 사용하려고하지 않는다면 "그냥 작동"할 것입니다. 특히, 많은 유형이 있습니다 IDisposable, 여러 객체 인스턴스가 공통 외부 자원을 조작 할 수있는 실제 위험이 있습니다 [예 : 객체는 List<> 생성 인스턴스의 경우, 구성 될 때 해당 목록에 인스턴스를 추가하고 인스턴스를 제거합니다. Dispose; 목록 작업이 동기화되지 않은 경우 비동기식 Dispose 하더라도 목록을 손상시킬 수 있습니다 대상이 폐기됩니다 그렇지 않으면 사용되지 않습니다.

BTW, 유용한 패턴은 객체가 사용중인 동안 비동기 처리를 허용하는 것입니다. 그러한 처분은 첫 번째 편리한 기회에서 진행중인 작업이 예외를 발생시킬 것으로 기대합니다. 소켓과 같은 것들이 이런 식으로 작동합니다. 소켓이 쓸모없는 상태로 소켓을 남기지 않고도 읽기 작업이 일찍 나갈 수는 없지만 소켓이 사용되지 않을 경우 다른 스레드가 다음을 결정한 경우 읽기가 데이터를 기다릴 필요가 없습니다. 포기해야합니다. IMHO, 그게 전부입니다 IDisposable 물체는 행동하기 위해 노력해야하지만, 그러한 일반적인 패턴을 요구하는 문서는 없다는 것을 알고 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top