У меня есть длинная работа, которую я накладываю на фоновый поток, используя TPL. То, что я сейчас работаю, но меня смущает, где я должен обращаться со своим AggregateException
во время запроса на отмену.Как правильно отменить задачу TPL с продолжением
В случае нажатия кнопки я начинаю процесс:
private void button1_Click(object sender, EventArgs e)
{
Utils.ShowWaitCursor();
buttonCancel.Enabled = buttonCancel.Visible = true;
try
{
// Thread cancellation.
cancelSource = new CancellationTokenSource();
token = cancelSource.Token;
// Get the database names.
string strDbA = textBox1.Text;
string strDbB = textBox2.Text;
// Start duplication on seperate thread.
asyncDupSqlProcs =
new Task<bool>(state =>
UtilsDB.DuplicateSqlProcsFrom(token, mainForm.mainConnection, strDbA, strDbB),
"Duplicating SQL Proceedures");
asyncDupSqlProcs.Start();
//TaskScheduler uiThread = TaskScheduler.FromCurrentSynchronizationContext();
asyncDupSqlProcs.ContinueWith(task =>
{
switch (task.Status)
{
// Handle any exceptions to prevent UnobservedTaskException.
case TaskStatus.Faulted:
Utils.ShowDefaultCursor();
break;
case TaskStatus.RanToCompletion:
if (asyncDupSqlProcs.Result)
{
Utils.ShowDefaultCursor();
Utils.InfoMsg(String.Format(
"SQL stored procedures and functions successfully copied from '{0}' to '{1}'.",
strDbA, strDbB));
}
break;
case TaskStatus.Canceled:
Utils.ShowDefaultCursor();
Utils.InfoMsg("Copy cancelled at users request.");
break;
default:
Utils.ShowDefaultCursor();
break;
}
}, TaskScheduler.FromCurrentSynchronizationContext()); // Or uiThread.
return;
}
catch (Exception)
{
// Do stuff...
}
}
В методе DuplicateSqlProcsFrom(CancellationToken _token, SqlConnection masterConn, string _strDatabaseA, string _strDatabaseB, bool _bCopyStoredProcs = true, bool _bCopyFuncs = true)
меня
DuplicateSqlProcsFrom(CancellationToken _token, SqlConnection masterConn, string _strDatabaseA, string _strDatabaseB, bool _bCopyStoredProcs = true, bool _bCopyFuncs = true)
{
try
{
for (int i = 0; i < someSmallInt; i++)
{
for (int j = 0; j < someBigInt; j++)
{
// Some cool stuff...
}
if (_token.IsCancellationRequested)
_token.ThrowIfCancellationRequested();
}
}
catch (AggregateException aggEx)
{
if (aggEx.InnerException is OperationCanceledException)
Utils.InfoMsg("Copy operation cancelled at users request.");
return false;
}
catch (OperationCanceledException)
{
Utils.InfoMsg("Copy operation cancelled at users request.");
return false;
}
}
В нажатие кнопки события (или с помощью delegate
(buttonCancel.Click + = делегат {/ Отменить задание /} ) I cancel the
Задача` следующим образом:
private void buttonCancel_Click(object sender, EventArgs e)
{
try
{
cancelSource.Cancel();
asyncDupSqlProcs.Wait();
}
catch (AggregateException aggEx)
{
if (aggEx.InnerException is OperationCanceledException)
Utils.InfoMsg("Copy cancelled at users request.");
}
}
Это ловит OperationCanceledException
штрафа в методе DuplicateSqlProcsFrom
и печатает мое сообщение, но в обратном вызове, представленной asyncDupSqlProcs.ContinueWith(task => { ... });
выше task.Status
всегда RanToCompletion
; его следует отменить!
Каков наилучший способ захвата и решения задачи Cancel()
в этом случае. Я знаю, как это делается в простых случаях, показанных в this example from the CodeProject, и от examples on MSDN, но в этом случае я запутался при выполнении продолжения.
Как я могу захватить задачу отмены в этом случае и как обеспечить правильное управление task.Status
?
Спасибо за это. Это действительно помогло. Я дошел до стадии удаления обработок из метода 'DuplicateSqlProcsFrom', но все еще пытался захватить его в другом месте. – MoonKnight
Я сделал то, что вы предлагаете, но в моем методе продолжения я получаю условие 'TaskStatus.Faulted', никогда не' TaskStatus.Cancelled'. Вы знаете, почему это может быть? – MoonKnight
Я добавил объяснение и решение этого поведения для ответа. – shambulator