[英]Asynchronous operations within an asynchronous operation
我的多線程知識還很初級,因此,這里的一些指針將非常有用。 我有一個接口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
實現,因此您不必實現其實質。 但是,您確實需要將一些額外的數據走私到IOperationInvoker.InvokeEnd
返回的IAsyncResult
。 您可以通過創建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%正確。 同樣,可以和應該在End
實現中處置Thread
和ManualResetEvent
,這應該與實現IDisposable
所有對象一起完成。 很顯然, End
應該檢查以確保它已經實現了正確的類,以獲取比強制轉換異常更好的異常。 我忽略了這些和其他細節,因為它們模糊了異步實現的基本機制。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.