How can I implement the lazy source of TaskCompletion?

If the task opened by my TaskCompletionSource object can never be called, how can I reject the calculation of the result if and until someone completes the task?

For example, I want to block other asynchronous execution threads until a ManualResetEvent message is issued using the following WaitOneAsync function. I end the TaskCompleationSource in the ThreadPool.RegisterWaitForSingleObject callback, which happens when WaitHandle is signaled. But if no one is waiting for the task, then I do not want RegisterWaitForSingleObject (and I do not want RegisterWaitForSingleObject if the task is expected after the WaitHandle message).

How can I change WaitOneAsync so that the work of calculating the result in RegisterWaitForSingleObject is done only after someone waits for TaskCompleationSource.Task?

I believe that the answer may lie in a custom TaskAwaiter, as described here Implement AsyncManualResetEvent, using Lazy <T> to determine if Scott Chamberlain expected the task , but I can not get my solution from his example ... :(

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;
}
+4
source share
2 answers

Usr, - Task await ed. , .

- AsyncLazy Stephen Cleary 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));
+4

, . TPL , - .

, API, , . ?

public static Func<Task<T>> CreateWaitOneAsyncFactory<T>(this WaitHandle waitHandle, Func<T> result) {
 return () => WaitOneAsync(waitHandle, result);
}

factory . , .

. , . #. API.


: await tcs.Task . , result . a Task, . , . API WaitOneAsync .

+1

Source: https://habr.com/ru/post/1659275/


All Articles