gpt4 book ai didi

c# - IAsyncResult.AsyncWaitHandle.WaitOne() 在回调之前完成

转载 作者:太空狗 更新时间:2023-10-29 17:37:22 30 4
gpt4 key购买 nike

代码如下:

class LongOp
{
//The delegate
Action longOpDelegate = LongOp.DoLongOp;
//The result
string longOpResult = null;

//The Main Method
public string CallLongOp()
{
//Call the asynchronous operation
IAsyncResult result = longOpDelegate.BeginInvoke(Callback, null);

//Wait for it to complete
result.AsyncWaitHandle.WaitOne();

//return result saved in Callback
return longOpResult;
}

//The long operation
static void DoLongOp()
{
Thread.Sleep(5000);
}

//The Callback
void Callback(IAsyncResult result)
{
longOpResult = "Completed";
this.longOpDelegate.EndInvoke(result);
}
}

这是测试用例:

[TestMethod]
public void TestBeginInvoke()
{
var longOp = new LongOp();
var result = longOp.CallLongOp();

//This can fail
Assert.IsNotNull(result);
}

如果运行,测试用例可能会失败。为什么?

关于 delegate.BeginInvoke 如何工作的文档很少。有没有人想分享任何见解?

更新这是一个微妙的竞争条件,在 MSDN 或其他地方没有很好的记录。正如接受的答案中所解释的那样,问题是当操作完成时,等待句柄发出信号,然后执行回调。该信号释放等待的主线程,现在 Callback 执行进入“竞赛”。 Jeffry Richter's suggested implementation显示幕后发生的事情:

  // If the event exists, set it   
if (m_AsyncWaitHandle != null) m_AsyncWaitHandle.Set();

// If a callback method was set, call it
if (m_AsyncCallback != null) m_AsyncCallback(this);

有关解决方案,请参阅 Ben Voigt 的回答。该实现不会产生第二个等待句柄的额外开销。

最佳答案

ASyncWaitHandle.WaitOne() 在异步操作完成时发出信号。同时调用 CallBack()。

这意味着 WaitOne() 之后的代码在主线程中运行,而 CallBack 在另一个线程中运行(可能与运行 DoLongOp() 的线程相同)。这会导致竞争条件,其中 longOpResult 的值在返回时基本上是未知的。

人们可能期望 ASyncWaitHandle.WaitOne() 会在 CallBack 完成时发出信号,但这不是它的工作方式;-)

您需要另一个 ManualResetEvent 让主线程等待 CallBack 设置 longOpResult。

关于c# - IAsyncResult.AsyncWaitHandle.WaitOne() 在回调之前完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4099318/

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