[英]Asynchronous operations within an asynchronous operation
My multi-threading knowledge is still pretty rudimentary, so would really appreciate some pointers here. 我的多线程知识还很初级,因此,这里的一些指针将非常有用。 I have an interface, IOperationInvoker (from WCF) which has the following methods:
我有一个接口IOperationInvoker(来自WCF),具有以下方法:
IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
Given a concrete implementation of this interface, I need to implement the same interface, whilst calling the underlying implementation in a seperate Thread. 给定此接口的具体实现,我需要实现相同的接口,同时在单独的线程中调用基础实现。 (in case you're wondering why, the concrete implmentation calls a legacy COM object which needs to be in a different apartment state).
(如果您想知道为什么,具体实现会调用需要处于不同单元状态的旧版COM对象)。
At the moment, I'm doing something like this: 目前,我正在执行以下操作:
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);
}
}
I'm thinking I need to wrap up the returned AsyncResult with my own, so I can get back to the thread we've spooled up... but honestly I'm a little out of my depth. 我在想我需要用自己的包装返回的AsyncResult,这样我就可以回到我们假脱机的线程中了……但是说实话,我有点不尽如人意。 Any pointers?
有指针吗?
Many thanks, 非常感谢,
James 詹姆士
The easiest way to implement a synchronous method asynchronously is to put it into a delegate, and use the BeginInvoke
and EndInvoke
methods on the resulting delegate. 异步实现同步方法的最简单方法是将其放入委托中,并在所得委托上使用
BeginInvoke
和EndInvoke
方法。 This will run the synchronous method on a threadpool thread, and BeginInvoke
will return an IAsyncResult
implementation, so you don't have to implement the guts of it. 这将在线程池线程上运行同步方法,并且
BeginInvoke
将返回IAsyncResult
实现,因此您不必实现其实质。 However, you do need to smuggle a little extra data into the IAsyncResult
returned by IOperationInvoker.InvokeEnd
. 但是,您确实需要将一些额外的数据走私到
IOperationInvoker.InvokeEnd
返回的IAsyncResult
。 You could do that easily by creating an implementation of IAsyncResult
that delegates everything to an inner IAsyncResult
, but has an extra field to contain the delegate, so that when the IAsyncResult
instance is passed to InvokeEnd
, you can access the delegate to call EndInvoke
on it. 您可以通过创建
IAsyncResult
的实现轻松地做到这一点,该实现将所有内容委派给内部IAsyncResult
,但是有一个额外的字段来包含委托,因此,当IAsyncResult
实例传递给InvokeEnd
,您可以访问委托以对其调用EndInvoke
。
However, after closer reading of your question, I see that you need to use an explicit thread with COM settings etc. 但是,仔细阅读您的问题后,我发现您需要使用带有COM设置等的显式线程。
What you need to do is properly implement IAsyncResult
. 您需要做的是正确实现
IAsyncResult
。 Almost everything follows from this, since the IAsyncResult
will contain all the bits needed for synchronization. 由于
IAsyncResult
将包含同步所需的所有位,因此几乎所有内容都随之而来。
Here's a very simple, but not terribly efficient, implementation of IAsyncResult
. 这是
IAsyncResult
的非常简单但效率不高的实现。 It encapsulates all the essential features: passing arguments, a synchronization event, callback implementation, propagating exceptions from async task and returning result. 它封装了所有基本功能:传递参数,同步事件,回调实现,从异步任务传播异常并返回结果。
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();
}
}
It's important for correctness that client code can't see the IAsyncResult
implementation, otherwise they might access methods like SignalException
inappropriately or read Result
prematurely. 客户端代码看不到
IAsyncResult
实现对于正确性很重要,否则客户端代码可能会不适当地访问SignalException
方法或过早读取Result
。 The class can be made more efficient by not constructing the WaitHandle
implementation ( ManualResetEvent
in the example) if it's not necessary, but this is tricky to get 100% right. 如果不需要,可以通过不构造
WaitHandle
实现(在示例中为ManualResetEvent
)来提高类的效率,但这很难使100%正确。 Also, the Thread
and ManualResetEvent
can and should be disposed of in the End
implementation, as should be done with all objects that implement IDisposable
. 同样,可以和应该在
End
实现中处置Thread
和ManualResetEvent
,这应该与实现IDisposable
所有对象一起完成。 And obviously, End
should check to make sure that it has gotten an implementation of the right class to get a nicer exception than a cast exception. 很显然,
End
应该检查以确保它已经实现了正确的类,以获取比强制转换异常更好的异常。 I've left these and other details out as they obscure the essential mechanics of the async implementation. 我忽略了这些和其他细节,因为它们模糊了异步实现的基本机制。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.