문제

내 멀티스레딩 지식은 아직 초보적이므로 여기에 몇 가지 조언을 해주시면 정말 감사하겠습니다.다음과 같은 메서드가 있는 IOperationInvoker(WCF의) 인터페이스가 있습니다.

IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)

이 인터페이스의 구체적인 구현이 주어지면 별도의 스레드에서 기본 구현을 호출하는 동시에 동일한 인터페이스를 구현해야 합니다.(이유가 궁금하신 경우 구체적인 구현에서는 다른 아파트 상태에 있어야 하는 레거시 COM 개체를 호출합니다.)

현재 저는 다음과 같은 일을 하고 있습니다.

public StaOperationSyncInvoker : IOperationInvoker {
   IOperationInvoker _innerInvoker;
   public StaOperationSyncInvoker(IOperationInvoker invoker) {
       this._innerInvoker = invoker;
   } 


    public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
    {
        Thread t = new Thread(BeginInvokeDelegate);
        InvokeDelegateArgs ida = new InvokeDelegateArgs(_innerInvoker, instance, inputs, callback, state);
        t.SetApartmentState(ApartmentState.STA);
        t.Start(ida);
        // would do t.Join() if doing syncronously
        // how to wait to get IAsyncResult?
        return ida.AsyncResult;
    }

    public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
    {
        // how to call invoke end on the 
        // thread? could we have wrapped IAsyncResult
        // to get a reference here?
        return null;
    }

    private class InvokeDelegateArgs {
        public InvokeDelegateArgs(IOperationInvoker invoker, object instance, object[] inputs, AsyncCallback callback, object state)
        {
            this.Invoker = invoker;
            this.Instance = instance;
            this.Inputs = inputs;
            this.Callback = callback;
            this.State = state;
        }

        public IOperationInvoker Invoker { get; private set; }
        public object Instance { get; private set; }
        public AsyncCallback Callback { get; private set; }
        public IAsyncResult AsyncResult { get; set; }
        public Object[] Inputs { get; private set; }
        public Object State { get; private set; }
    }
    private static void BeginInvokeDelegate(object data)
    {
        InvokeDelegateArgs ida = (InvokeDelegateArgs)data;
        ida.AsyncResult = ida.Invoker.InvokeBegin(ida.Instance, ida.Inputs, ida.Callback, ida.State);
    }
}

반환된 AsyncResult를 자체적으로 마무리해야 한다고 생각합니다. 그러면 우리가 스풀링한 스레드로 돌아갈 수 있습니다...하지만 솔직히 나는 좀 부족해요.어떤 조언이 있습니까?

정말 감사합니다.

제임스

도움이 되었습니까?

해결책

동기 메서드를 비동기식으로 구현하는 가장 쉬운 방법은 이를 대리자에 넣고 BeginInvoke 그리고 EndInvoke 결과 대리자에 대한 메서드입니다.그러면 스레드 풀 스레드에서 동기 메서드가 실행되고 BeginInvoke 반환합니다 IAsyncResult 구현하므로 내장을 구현할 필요가 없습니다.그러나 약간의 추가 데이터를 IAsyncResult 에 의해 반환됨 IOperationInvoker.InvokeEnd.구현을 생성하면 쉽게 할 수 있습니다. IAsyncResult 모든 것을 내부에 위임하는 것 IAsyncResult, 이지만 대리자를 포함하는 추가 필드가 있으므로 IAsyncResult 인스턴스가 다음으로 전달됩니다. InvokeEnd, 대리인에게 액세스하여 전화를 걸 수 있습니다. EndInvoke 그 위에.

그러나 귀하의 질문을 자세히 읽은 후에는 COM 설정 등이 포함된 명시적 스레드를 사용해야 한다는 것을 알았습니다.

당신이해야 할 일은 올바르게 구현하는 것입니다 IAsyncResult.거의 모든 것이 이것으로부터 이어집니다. IAsyncResult 동기화에 필요한 모든 비트가 포함됩니다.

다음은 매우 간단하지만 그다지 효율적이지는 않은 구현입니다. IAsyncResult.이는 모든 필수 기능을 캡슐화합니다.인수 전달, 동기화 이벤트, 콜백 구현, 비동기 작업에서 예외 전파 및 결과 반환.

using System;
using System.Threading;

class MyAsyncResult : IAsyncResult
{
    object _state;
    object _lock = new object();
    ManualResetEvent _doneEvent = new ManualResetEvent(false);
    AsyncCallback _callback;
    Exception _ex;
    bool _done;
    int _result;
    int _x;

    public MyAsyncResult(int x, AsyncCallback callback, object state)
    {
        _callback = callback;
        _state = state;
        _x = x; // arbitrary argument(s)
    }

    public int X { get { return _x; } }

    public void SignalDone(int result)
    {
        lock (_lock)
        {
            _result = result;
            _done = true;
            _doneEvent.Set();
        }
        // never invoke any delegate while holding a lock
        if (_callback != null)
            _callback(this); 
    }

    public void SignalException(Exception ex)
    {
        lock (_lock)
        {
            _ex = ex;
            _done = true;
            _doneEvent.Set();
        }
        if (_callback != null)
            _callback(this);
    }

    public object AsyncState
    {
        get { return _state; }
    }

    public WaitHandle AsyncWaitHandle
    {
        get { return _doneEvent; }
    }

    public bool CompletedSynchronously
    {
        get { return false; }
    }

    public int Result
    {
        // lock (or volatile, complex to explain) needed
        // for memory model problems.
        get
        {
            lock (_lock)
            {
                if (_ex != null)
                    throw _ex;
                return _result;
            }
        }
    }

    public bool IsCompleted
    {
        get { lock (_lock) return _done; }
    }
}

class Program
{
    static void MyTask(object param)
    {
        MyAsyncResult ar = (MyAsyncResult) param;
        try
        {
            int x = ar.X;
            Thread.Sleep(1000); // simulate lengthy work
            ar.SignalDone(x * 2); // demo work = double X
        }
        catch (Exception ex)
        {
            ar.SignalException(ex);
        }
    }

    static IAsyncResult Begin(int x, AsyncCallback callback, object state)
    {
        Thread th = new Thread(MyTask);
        MyAsyncResult ar = new MyAsyncResult(x, callback, state);
        th.Start(ar);
        return ar;
    }

    static int End(IAsyncResult ar)
    {
        MyAsyncResult mar = (MyAsyncResult) ar;
        mar.AsyncWaitHandle.WaitOne();
        return mar.Result; // will throw exception if one 
                           // occurred in background task
    }

    static void Main(string[] args)
    {
        // demo calling code
        // we don't need state or callback for demo
        IAsyncResult ar = Begin(42, null, null); 
        int result = End(ar);
        Console.WriteLine(result);
        Console.ReadLine();
    }
}

클라이언트 코드가 IAsyncResult 구현하지 않으면 다음과 같은 메소드에 액세스할 수 있습니다. SignalException 부적절하게 읽거나 Result 조기에.클래스를 구성하지 않음으로써 클래스를 보다 효율적으로 만들 수 있습니다. WaitHandle 구현 (ManualResetEvent 예에서는) 필요하지 않은 경우 100% 올바르게 하기가 까다롭습니다.또한, Thread 그리고 ManualResetEvent 폐기할 수 있고 폐기해야 합니다. End 구현하는 모든 객체에 대해 수행되어야 하는 것처럼 구현 IDisposable.그리고 분명히, End 캐스트 예외보다 더 좋은 예외를 얻으려면 올바른 클래스의 구현을 얻었는지 확인해야 합니다.비동기 구현의 필수 메커니즘을 모호하게 만들기 때문에 이러한 세부 사항과 기타 세부 사항은 생략했습니다.

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