Я использую BackgroundWorker для выполнения долгого вычисления (только одно такое вычисление за один раз).
У пользователя есть возможность отмены рабочего (вызывающий рабочего. CancelAsync).
В рабочем. Метод DoWork я периодически проверяю на флаг ожидания отмены и затем возвращаюсь из метода.
Затем событие Completed генерируется от рабочего, и я могу проверить, что рабочий был отменен. Кроме того, и это - важная вещь, я делаю некоторую дополнительную очистку, когда отмена обнаруживается.
Я уверен, что могла быть проблема, если пользователь отменяет рабочего, и она уже возвращается из метода DoWork. В этом случае я действительно хотел бы знать, что рабочий был отменен так, я мог очистка...
Существует ли лучший способ обработать процедуру отмены, с очисткой, рабочего?
Ваш обработчик событий DoWork
shoud периодически проверяют BackgroundWorker. CancellationPending
и набор DoWorkEventArgs. Отменить
к истинному прежде, чем возвратиться, если это было отменено.
Обработчик событий RunWorureCompleted
должен проверить свойство RunWoreyCompletedEventArgs.Canceled
, чтобы определить, отменен ли обработчик событий DoWork
(установите значение DoWorkEventArgs.Cancel
).
В случае условия гонки может случиться так, что пользователь запросил отмену ( BackgroundWorker.Depending
имеет значение true), но работник ее не увидел ( RunWoreyCompletedEventArgs.Canceled
имеет значение false). Вы можете проверить эти два свойства, чтобы определить, что это произошло, и сделать все, что вы выбрали (либо рассматривать это как успешное завершение - потому что работник действительно закончил успешно, или как отмену - потому что пользователь отменил и больше не волнует).
Я не вижу никакой ситуации, когда есть какая-либо неясность в том, что произошло.
EDIT
В ответ на комментарий - если существует несколько классов, которые должны обнаружить Pending
, нет никакой альтернативы передаче этим классам ссылки на тип, такой как BackgroundWorker
, который позволяет им получить эту информацию. Вы можете абстрагировать это в интерфейс,это то, что я обычно делаю, как описано в этом ответе на вопрос о BackgroundWorkers. Однако необходимо передать ссылку на тип, реализующий этот интерфейс, рабочим классам.
Если необходимо, чтобы рабочие классы могли задавать DoWorkEventArgs.Cancel
, необходимо либо передать ссылку на это, либо принять другое соглашение (например, логическое возвращаемое значение или пользовательское исключение), которое позволяет рабочим классам указывать, что произошла отмена.
] Не видя своего кода, немного сложно вносить предложения, но одно можно сделать - отключить кнопку "Отмена", когда пользователь нажимает на нее, а также при выходе из метода [] DoWork [
]. [
]Если пользователь также может отменить метод нажатием кнопки, то Вам также необходимо отключить его.[
] []Также - если метод []DoWork[
] закончен, то пользователю ничего не нужно "Отменить" - или я что-то пропустил. В таком случае, даже если вы не отключите кнопку отмены, ничего лишнего делать не нужно.[
]Зачем нужно видеть флаг отмены после того, как работник выполнил свою работу? Ты все еще хочешь вернуть то, что когда-либо было изменено?[
]] Есть ли причина, по которой вы не можете выполнять очистку в конце метода, который вы выполняете асинхронно? [
] []Обычно я использую такую структуру [
] [private void MyThreadMethod()
{
try
{
// Thread code
}
finally
{
// Cleanup
}
}
]
[]Я использую только полное событие для выполнения таких задач, как обновление пользовательского интерфейса, а не для очистки после потока. [
]] Гарантируется, что у вас не будет гонки в обработчике событий RunWorkerCompleted, так как он работает на потоке UI. Это всегда должно работать:[
] [private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
var bgw = sender as BackgroundWorker;
if (e.Cancelled || bgw.CancellationPending) {
// etc..
}
}
]