Отмена всей задачи, когда вызванный метод не возвращается

У меня есть метод, который регистрирует фоновую задачу, которая выглядит так:

//snippet from task builder method
        try
        {
            cancellationTokenSource.CancelAfter(10000);
            btr = Task.Run(() => registerTask(builder, btr,cancellationTokenSource.Token), cancellationTokenSource.Token).Result;
        }
        catch (OperationCanceledException) // something went wrong
        {
            return null;
        }



private BackgroundTaskRegistration registerTask(BackgroundTaskBuilder builder, BackgroundTaskRegistration btr, CancellationToken token)
{
    CancellationTokenSource newToken = new CancellationTokenSource();
    Task cancelledCheck = Task.Run(() =>
    {
        while (true)
        {
            if (token.IsCancellationRequested)
            {
                newToken.Cancel();
                token.ThrowIfCancellationRequested();
            }
        }
    }, newToken.Token);
    btr = Task.Run(()=> builder.Register(),token).Result;
    return btr;
}

Моя проблема в том, что иногда метод builder.Register() ничего не возвращает. Вероятно, это какая-то ошибка Windows; метод Register() никогда не завершается внутри. Действительно, через 10 секунд вызывается метод token.ThrowIfCancellationRequested(), но он не вызывает исключение в операторе try-catch, где он вызывается. Первоначально я вызывал builder.Register() напрямую без Task.Run(), но это не сработало, и это тоже.

Однако, если я заменю btr = Task.Run(() =>... на Task.Delay(ms) вместо ms > 10000, произойдет ожидаемый эффект.

Я делаю что-то неправильно? Или есть лучший способ сделать это? По сути, мне просто нужен код, который заставит метод registerTask() возвращать значение null, если builder.Register() не завершится через несколько секунд.


person Tyress    schedule 06.07.2016    source источник
comment
Использование .Result проблематично, так как это заблокирует поток; можно ли вместо этого использовать асинхронные функции и await?   -  person Jacob    schedule 07.07.2016
comment
@Jacob Возможно, это то, что происходит? Я делаю это из проекта среды выполнения Windows, поэтому я не могу сделать свою задачу асинхронной, моя ошибка компиляции говорит что-то вроде того, что я должен изменить тип Task на IAsyncAction или что-то в этом роде, но я еще этого не сделал   -  person Tyress    schedule 07.07.2016


Ответы (1)


Замена кода на что-то вроде этого сработала для меня:

    btr = null;
    cancellationTokenSource.CancelAfter(10000);
    Task registerTask = Task.Factory.StartNew(() =>
    {
      btr = builder.Register();
    });
   Task cancellationTask = Task.Factory.StartNew(() =>
   {
     while (true)
     {
       if (cancellationTokenSource.Token.IsCancellationRequested) break;
     }
     }, cancellationTokenSource.Token);
   Task[] tasks = new Task[2] { cancellationTask, registerTask };
   Task.WaitAny(tasks);

Вместо обработки ошибки получение запроса на отмену приведет к завершению одной из задач, и когда она завершится, я верну переменную регистрации задачи, независимо от того, является ли она нулевой или нет.

person Tyress    schedule 07.07.2016