gpt4 book ai didi

c# - 异步操作中的异步操作

转载 作者:太空宇宙 更新时间:2023-11-03 14:36:36 30 4
gpt4 key购买 nike

我的多线程知识还很初级,所以非常感谢这里的一些指示。我有一个接口(interface) IOperationInvoker(来自 WCF),它具有以下方法:

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

鉴于此接口(interface)的具体实现,我需要实现相同的接口(interface),同时在单独的线程中调用底层实现。 (如果您想知道为什么,具体实现调用需要处于不同单元状态的遗留 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,这样我就可以回到我们已经假脱机的线程……但老实说,我有点力不从心。有什么指点吗?

非常感谢,

詹姆斯

最佳答案

异步实现同步方法的最简单方法是将其放入委托(delegate)中,并在生成的委托(delegate)上使用 BeginInvokeEndInvoke 方法。这将在线程池线程上运行同步方法,BeginInvoke 将返回一个 IAsyncResult 实现,因此您不必实现它的核心部分。但是,您确实需要将一些额外数据偷运到 IOperationInvoker.InvokeEnd 返回的 IAsyncResult 中。您可以通过创建 IAsyncResult 的实现来轻松做到这一点,该实现将所有内容委托(delegate)给内部 IAsyncResult,但有一个额外的字段来包含委托(delegate),因此当 IAsyncResult 实例传递给 InvokeEnd,您可以访问委托(delegate)以在其上调用 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% 正确。此外,ThreadManualResetEvent 可以而且应该在 End 实现中处理掉,所有实现 的对象都应该这样做IDisposable。显然,End 应该检查以确保它已经获得了正确类的实现,以获得比转换异常更好的异常。我省略了这些和其他细节,因为它们模糊了异步实现的基 native 制。

关于c# - 异步操作中的异步操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/763417/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com