题
我的多线程知识仍然是相当简陋的,所以会很欣赏这里的一些指针。我有其具有如下的方法的接口,IOperationInvoker(来自WCF):
IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
给定一个具体实现这个接口的,我要实现相同的接口,同时呼吁在一个单独的线程的底层实现。 (如果你想知道为什么,具体implmentation调用它需要在不同的公寓状态的传统的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
de实现(ManualResetEvent
中的例子),如果它没有必要进行更有效的,但是这是棘手得到100%的正确。此外,Thread
和ManualResetEvent
可以而且应该在End
实施处置,如应实现IDisposable
所有对象来完成。很显然,End
应该检查,以确保它已经得到了正确的类的实现来获得比铸造异常的漂亮异常。我已经离开了这些和其他细节了,因为他们混淆了异步执行的基本机制。