Запуск не может быть вызван для задачи, которая завершилась исключение для задачи, которая не запускалась

Я работаю над мобильным приложением, разработанным с помощью Xamarin, и время от времени получаю отчеты о сбое приложения из-за следующего исключения:

System.InvalidOperationException Start нельзя вызывать для завершенной задачи.

Чтобы было ясно, это более или менее структура функции, в которой это происходит:

    CancellationTokenSource tokenSource;

    void Function(bool condition1, bool condition2)
    {
        if (tokenSource != null)
        {
            tokenSource.Cancel();
            tokenSource.Dispose();
            tokenSource = null;
        }

        Task completionTask = null;

        if (condition1)
        {
            tokenSource = new CancellationTokenSource();
            completionTask = new Task(async () =>
                {
                    await Task.Delay(1000);
                    if (tokenSource != null && !tokenSource.IsCancellationRequested)
                    {
                        InvokeOnMainThread(Function2);
                    }
                }, tokenSource.Token);
        }

        if (condition2)
        {
            TaskFactory.StartNew(() =>
                {
                  ...
                }).ContinueWith(() =>
                {
                    if (completionTask != null)
                    {
                        completionTask.Start();
                    }
                });
        }
        else
        {
            if (completionTask != null)
            {
                completionTask.Start();
            }
        }
    }

    void Function2()
    {
        if (tokenSource != null)
        {
            tokenSource.Cancel();
            tokenSource.Dispose();
            tokenSource = null;
        }
    }

Мне не удается воспроизвести ошибку, а также я не уверен, как это возможно, что completionTask уже был запущен, так как он может быть запущен только один раз. Даже если по какой-либо причине Function вызывается последовательно или несколькими потоками, это не должно вызывать никаких проблем, поскольку completionTask является локальной переменной.

Любая идея о том, что может быть причиной?


person papafe    schedule 01.06.2016    source источник
comment
В задаче есть свойство или метод, чтобы проверить, завершена ли она. msdn.microsoft .com/en-us/library/   -  person Callum Linington    schedule 01.06.2016
comment
если оба условия1 и условие2 верны, мне кажется, что вы можете попытаться запустить завершение задачи дважды.   -  person user6144226    schedule 01.06.2016
comment
Кстати, общее мнение таково, что не следует использовать конструкторы задач.   -  person Charles Mager    schedule 01.06.2016
comment
@CallumLinington Это правда, и я знаю об этом. Но вот проблема в том, что я не знаю, как это возможно, что задача запускалась дважды.   -  person papafe    schedule 01.06.2016
comment
@user6144226 user6144226 Если условие1 истинно, то завершениеTask просто создается, а не запускается. Если верно, то вне зависимости от условия2 он будет запущен   -  person papafe    schedule 01.06.2016
comment
Я не могу представить, что ваша реализация решает проблему наилучшим образом, было бы лучше, если бы вы могли указать проблему, которую пытаетесь решить.   -  person Callum Linington    schedule 01.06.2016
comment
@CallumLinington Я понимаю вашу точку зрения, но я хотел удалить все ненужные части из своего кода, чтобы сосредоточиться на исключении. То, что, возможно, код плохо структурирован или не самый лучший, это уже другая история.   -  person papafe    schedule 01.06.2016
comment
Да, и, возможно, правильное решение этой истории приведет к решению без ошибок. иначе известный как решение XY   -  person Callum Linington    schedule 01.06.2016
comment
@CallumLinington Я понимаю, почему вы думаете, что это проблема XY, но я так не думаю. В данном случае мой вопрос был не о решении конкретной проблемы, а о том, как мой код мог вызвать исключение. И, кажется, я тоже понял, почему.   -  person papafe    schedule 01.06.2016


Ответы (1)


Я думаю, что это состояние гонки для cancelToken, поскольку оно распространяется на несколько вызовов функций. Таким образом, вы можете попытаться запустить задачу, которая отменена функцией2 или другим вызовом той же функции.

person user6144226    schedule 01.06.2016
comment
Привет, можете ли вы предоставить последовательность событий, которые могут вызвать такую ​​​​проблему? - person papafe; 01.06.2016
comment
Я просто запускаю функцию 10 раз в цикле. Как ни странно, я не смог воспроизвести это на Fiddle: dotnetfiddle.net/Widget/2sstvm - person user6144226; 01.06.2016
comment
@markusian Я на самом деле нахожу это довольно странным, вы нигде не ждете этих задач? - person user6144226; 01.06.2016
comment
Я не думаю, что странно, что вы не смогли это воспроизвести, потому что я не понимаю, что задача может быть запущена до вызова .Start(), даже если Function вызывается несколько раз. Что касается ожидающих задач... ну, мне их не нужно ждать :) - person papafe; 01.06.2016
comment
Поскольку вы не ждете вызовов END, второй запуск той же функции МОЖЕТ попытаться запустить новую задачу, которая может быть отменена с использованием того же токена отмены из первого (или любого предыдущего) запуска. - person user6144226; 01.06.2016
comment
Даже если новая задача может быть отменена с использованием более старого токена отмены (из предыдущего запуска), я не уверен, как это может вызвать исключение, которое я вижу. - person papafe; 01.06.2016
comment
@markusian документы в Start.Task указывают именно на это. Вы ожидаете, что он скажет «отменено», а не «завершено». msdn.microsoft.com/en-us/ библиотека/dd270682%28v=vs.110%29.aspx - person user6144226; 01.06.2016
comment
На самом деле я думаю, что, возможно, я неправильно понял ваши слова раньше. В любом случае такое исключение может произойти, если источник токена отмены будет отменен до того, как мы начнем задачу. Когда вызывается .Start(), мы получаем исключение - person papafe; 01.06.2016