nos*_*tio 29 .net c# multithreading task-parallel-library async-await
我想等待手动重置事件,超时并观察取消.我想出了类似下面的东西.手动重置事件对象由我无法控制的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
}
Run Code Online (Sandbox Code Playgroud)
将帖子显然,这是有道理的使用RegisterWaitForSingleObject.我试试看.
Ste*_*ary 45
RegisterWaitForSingleObject将等待组合到专用的服务器线程上,每个线程都可以在多个句柄上等待(具体来说,其中有63个,MAXIMUM_WAIT_OBJECTS对于"控制"句柄是减1).
所以你应该可以使用这样的东西(警告:未经测试):
public static class WaitHandleExtensions
{
public static Task AsTask(this WaitHandle handle)
{
return AsTask(handle, Timeout.InfiniteTimeSpan);
}
public static Task AsTask(this WaitHandle handle, TimeSpan timeout)
{
var tcs = new TaskCompletionSource<object>();
var registration = ThreadPool.RegisterWaitForSingleObject(handle, (state, timedOut) =>
{
var localTcs = (TaskCompletionSource<object>)state;
if (timedOut)
localTcs.TrySetCanceled();
else
localTcs.TrySetResult(null);
}, tcs, timeout, executeOnlyOnce: true);
tcs.Task.ContinueWith((_, state) => ((RegisteredWaitHandle)state).Unregister(null), registration, TaskScheduler.Default);
return tcs.Task;
}
}
Run Code Online (Sandbox Code Playgroud)
Mil*_*les 11
您还可以使用与ManualResetEvent类似的SemaphoreSlim.WaitAsync()
斯蒂芬的克利里解决方案看起来很完美。Microsoft 提供了类似的一种。
因为我还没有看到带有取消逻辑的示例。
这里是:
public static class WaitHandleExtensions
{
public static Task WaitOneAsync(this WaitHandle waitHandle, CancellationToken cancellationToken, int timeoutMilliseconds = Timeout.Infinite)
{
if (waitHandle == null)
throw new ArgumentNullException(nameof(waitHandle));
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
CancellationTokenRegistration ctr = cancellationToken.Register(() => tcs.TrySetCanceled());
TimeSpan timeout = timeoutMilliseconds > Timeout.Infinite ? TimeSpan.FromMilliseconds(timeoutMilliseconds) : Timeout.InfiniteTimeSpan;
RegisteredWaitHandle rwh = ThreadPool.RegisterWaitForSingleObject(waitHandle,
(_, timedOut) =>
{
if (timedOut)
{
tcs.TrySetCanceled();
}
else
{
tcs.TrySetResult(true);
}
},
null, timeout, true);
Task<bool> task = tcs.Task;
_ = task.ContinueWith(_ =>
{
rwh.Unregister(null);
return ctr.Unregister();
}, CancellationToken.None);
return task;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
16452 次 |
| 最近记录: |