我想等待一个手动重置事件与超时和观察取消。我想到了下面的东西。手动重置事件对象是由一个API提供的,超出了我的控制范围。有没有一种方法可以在不占用和阻塞ThreadPool中的线程的情况下实现这一点?
static Task<bool> TaskFromWaitHandle(WaitHandle mre, int timeout, CancellationToken ct)
{
return Task.Run(() =>
{
bool s = WaitHandle.WaitAny(new WaitHandle[] { mre, ct.WaitHandle }, timeout) == 0;
ct.ThrowIfCancellationRequested();
return s;
}, ct);
}
// ...
if (await TaskFromWaitHandle(manualResetEvent, 1000, cts.Token))
{
// true if event was set
}
else
{
// false if timed out, exception if cancelled
}
**[编辑]**显然,它makes sense使用RegisterWaitForSingleObject
。我会给予的。
6条答案
按热度按时间toiithl61#
RegisterWaitForSingleObject
将把等待合并到专用的waiter线程上,每个waiter线程可以等待多个句柄(具体来说,63个句柄,即MAXIMUM_WAIT_OBJECTS
减去一个“控制”句柄)。所以你应该能够使用这样的东西(警告:未测试):
hc8w905p2#
您还可以使用SemaphoreSlim.WaitAsync(),它类似于ManualResetEvent
iswrvxsc3#
Stephen的Cleary解决方案看起来很完美。微软提供了类似的一个。
因为我还没有看到一个取消逻辑的例子。
这就是:
eufgjt7s4#
您可以给予一下https://www.badflyer.com/asyncmanualresetevent,它试图在https://blogs.msdn.com/b/pfxteam/archive/2012/02/11/10266920.aspx上构建示例,以支持超时和取消。
2cmtqfgy5#
替代解决方案:等待任务句柄和手动重置事件
我在使用
Task.WaitAny()
和Task
(由SqlConnection.OpenAsync()')返回)以及作为参数接收并 Package 在Task
和AsTask()
中的手动重置事件时发生了内存泄漏。这些对象未被释放:TaskCompletionSource<Object>, Task<Object>, StandardTaskContinuation, RegisteredWaitHandle, RegisteredWaithandleSafe, ContinuationResultTaskFromresultTask<Object,bool>, _ThreadPoolWaitOrTimerCallback
)。这是在Windows服务中使用的一个函数的真实的生产代码,该函数试图在循环中打开到db的连接,直到连接打开,或操作失败,或在包含此代码的函数中作为参数接收的
ManualResetEvent _finishRequest
被任何其他线程中的代码发出信号。为了避免泄密,我决定反过来做:等待
OpenAsync()
返回的_finishRequest
和Task
的句柄:如果你还需要超时,你可以将它包含在对
OpenAsync
的调用中,或者你的asyn函数中,然后检查异步操作的结果是否因为超时而被取消:完成后检查任务的状态,如代码注解中的NOTE所示。ttp71kqs6#
安装
Microsoft.VisualStudio.Threading
包,然后您将能够使用AsyncManualResetEvent
类,其自己的文档指出:一种可以异步等待的ManualResetEvent。
文档:https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.threading.asyncmanualresetevent