RegisterWaitForSingleObject

RegisterWaitForSingleObject

如果我的TaskCompletionSource公开的Task可能永远不会被调用,那么除非有人等到任务等待,我如何才能将结果的计算推迟?

例如,我想阻止其他异步执行线程,直到使用以下函数WaitOneAsync发出ManualResetEvent信号为止。我在ThreadPool.RegisterWaitForSingleObject的回调中完成TaskCompleationSource,这在发出WaitHandle信号时发生。但是,如果没有人等待任务,那么我就不想注册RegisterWaitForSingleObject(如果在信号WaitHandle之后等待任务,我也不想注册RegisterWaitForSingleObject)。

如何更改WaitOneAsync,以便将结果计算到RegisterWaitForSingleObject的工作仅在有人等待TaskCompleationSource.Task之后发生?

我相信答案可能在于斯科特·张伯伦(Scott Chamberlain)此处Implement AsyncManualResetEvent using Lazy<T> to determine if the task has been awaited中描述的自定义TaskAwaiter,但我不能完全从他的示例中得到解决方案... :(

public static async Task<T> WaitOneAsync<T>(this WaitHandle waitHandle, Func<T> result) {

    var tcs = new TaskCompletionSource<T>();

    RegisteredWaitHandle rwh = null;
    rwh = ThreadPool.RegisterWaitForSingleObject(
        waitObject: waitHandle,
        callBack: (s, t) => {
            rwh.Unregister(null);
            tcs.TrySetResult(result());
        },
        state: null,
        millisecondsTimeOutInterval: -1,
        executeOnlyOnce: true
    );

    return await tcs.Task;
}

最佳答案

正如usr所说,无法对Task被ed编码的代码使用react。但是,如果您可以使用自定义的awaitable,则可以。

一种简单的方法是使用 await from Stephen Cleary's AsyncEx:

private static Task<T> WaitOneAsyncImpl<T>(WaitHandle waitHandle, Func<T> result)
{
    if (waitHandle.WaitOne(0))
        return Task.FromResult(result());

    var tcs = new TaskCompletionSource<T>();

    RegisteredWaitHandle rwh = null;
    rwh = ThreadPool.RegisterWaitForSingleObject(
        waitObject: waitHandle,
        callBack: (s, t) =>
        {
            rwh.Unregister(null);
            tcs.TrySetResult(result());
        },
        state: null,
        millisecondsTimeOutInterval: -1,
        executeOnlyOnce: true
    );

    return tcs.Task;
}

public static AsyncLazy<T> WaitOneAsync<T>(this WaitHandle waitHandle, Func<T> result)
    => new AsyncLazy<T>(() => WaitOneAsyncImpl(waitHandle, result));

10-06 13:41