简体   繁体   中英

How to schedule a TaskCompletionSource.Task with a TaskScheduler?

    public Task<bool> Submit(TaskScheduler ts, Func<bool> work, object state, TaskContinuationOptions taskContinuationOptions)
    {
        TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(state, TaskCreationOptions.None);

        Task t1 = new TaskFactory(_cts.Token, TaskCreationOptions.None, taskContinuationOptions, ts).StartNew(() =>
        {
            try
            {
                tcs.SetResult(work());
            }
            catch(Exception e)
            {
                tcs.SetException(e);
            }               
        });

        Task<bool> t2 = tcs.Task;
        t2.ContinueWith(OnTaskSignaled);
        return t2;
    }

    public void OnTaskSignaled(Task<bool> signaledTask) 
    {            
        BusinessItem item = (BusinessItem)signaledTask.AsyncState;
        if (signaledTask.IsCanceled)
        {
            Console.WriteLine("{0} cancelled: Invalid State", item.Id);
        }
        else if (signaledTask.IsFaulted)
        {
            Console.WriteLine("{0} threw: {1}", item.Id, signaledTask.Exception);
        }
        else if (signaledTask.Result == true)
        {
            Console.WriteLine("{0} Succeeded", item.Id);
            // continue to submit
        }
        else if (signaledTask.Result == false)
        {
            Console.WriteLine("{0} Incomplete, retry", item.Id);
            Submit(_ts2, item.Work, item);
        }
    }

In the above example, does the taskContinuationOptions option propagate to TaskCompletionSource.Task? In debug mode, I can see that t1 and t2 are two different objects. In fact, if state is passed to StartNew(...), it is only available to t1, but not t2.

TaskFactory in this case is used only to submit work to a specific TaskScheduler, ts. The fact that it also creates another task makes the code confusing. Is there a less confusing way to do this? I don't understand why TaskCompletionSource being a Task producer is not as configurable as TaskFactory.

There is no reason for you to use TaskCompletionSource . If you return the value from the lambda, the Task returned from StartNew() will contain exactly what you want: the result on success and the exception on failure.

Also, I think the TaskContinuationOptions in TaskFactory work only for continuations that are started directly through the factory (eg using ContinueWhenAll() ). Because of that, I think you don't need the TaskFactory at all, but you should specify the options to each task (the original and the continuation) separately. Though I think it's weird that someone outside of the current method should set how the internal continuation should execute.

And to answer your question: it doesn't make sense to schedule TaskCompletionSource with some TaskFactory , because TaskCompletionSource doesn't actually execute.

With these changes, your code will look like this:

public Task<bool> Submit(
    TaskScheduler ts, Func<bool> work, object state,
    TaskContinuationOptions taskContinuationOptions)
{
    var task = Task.Factory.StartNew(_ => work(), state, _cts.Token);

    task.ContinueWith(OnTaskSignaled, _cts.Token, taskContinuationOptions,
                      TaskScheduler.Default);

    return task;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM