Отмена BackgroundWorker, как предотвратить гонку, когда это уже закончилось

Я использую BackgroundWorker для выполнения долгого вычисления (только одно такое вычисление за один раз).

У пользователя есть возможность отмены рабочего (вызывающий рабочего. CancelAsync).

В рабочем. Метод DoWork я периодически проверяю на флаг ожидания отмены и затем возвращаюсь из метода.

Затем событие Completed генерируется от рабочего, и я могу проверить, что рабочий был отменен. Кроме того, и это - важная вещь, я делаю некоторую дополнительную очистку, когда отмена обнаруживается.

Я уверен, что могла быть проблема, если пользователь отменяет рабочего, и она уже возвращается из метода DoWork. В этом случае я действительно хотел бы знать, что рабочий был отменен так, я мог очистка...

Существует ли лучший способ обработать процедуру отмены, с очисткой, рабочего?

5
задан Stécy 8 January 2010 в 20:17
поделиться

4 ответа

Ваш обработчик событий DoWork shoud периодически проверяют BackgroundWorker. CancellationPending и набор DoWorkEventArgs. Отменить к истинному прежде, чем возвратиться, если это было отменено.

Обработчик событий RunWorureCompleted должен проверить свойство RunWoreyCompletedEventArgs.Canceled , чтобы определить, отменен ли обработчик событий DoWork (установите значение DoWorkEventArgs.Cancel ).

В случае условия гонки может случиться так, что пользователь запросил отмену ( BackgroundWorker.Depending имеет значение true), но работник ее не увидел ( RunWoreyCompletedEventArgs.Canceled имеет значение false). Вы можете проверить эти два свойства, чтобы определить, что это произошло, и сделать все, что вы выбрали (либо рассматривать это как успешное завершение - потому что работник действительно закончил успешно, или как отмену - потому что пользователь отменил и больше не волнует).

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

EDIT

В ответ на комментарий - если существует несколько классов, которые должны обнаружить Pending , нет никакой альтернативы передаче этим классам ссылки на тип, такой как BackgroundWorker , который позволяет им получить эту информацию. Вы можете абстрагировать это в интерфейс,это то, что я обычно делаю, как описано в этом ответе на вопрос о BackgroundWorkers. Однако необходимо передать ссылку на тип, реализующий этот интерфейс, рабочим классам.

Если необходимо, чтобы рабочие классы могли задавать DoWorkEventArgs.Cancel , необходимо либо передать ссылку на это, либо принять другое соглашение (например, логическое возвращаемое значение или пользовательское исключение), которое позволяет рабочим классам указывать, что произошла отмена.

2
ответ дан 14 December 2019 в 19:15
поделиться
[

] Не видя своего кода, немного сложно вносить предложения, но одно можно сделать - отключить кнопку "Отмена", когда пользователь нажимает на нее, а также при выходе из метода [] DoWork []. [

] [

]Если пользователь также может отменить метод нажатием кнопки, то Вам также необходимо отключить его.[

] [

]Также - если метод []DoWork[] закончен, то пользователю ничего не нужно "Отменить" - или я что-то пропустил. В таком случае, даже если вы не отключите кнопку отмены, ничего лишнего делать не нужно.[

] [

]Зачем нужно видеть флаг отмены после того, как работник выполнил свою работу? Ты все еще хочешь вернуть то, что когда-либо было изменено?[

]
0
ответ дан 14 December 2019 в 19:15
поделиться
[

] Есть ли причина, по которой вы не можете выполнять очистку в конце метода, который вы выполняете асинхронно? [

] [

]Обычно я использую такую структуру [

] [
private void MyThreadMethod()
{
    try
    {
        // Thread code
    }
    finally 
    {
        // Cleanup
    }
}
] [

]Я использую только полное событие для выполнения таких задач, как обновление пользовательского интерфейса, а не для очистки после потока. [

]
0
ответ дан 14 December 2019 в 19:15
поделиться
[

] Гарантируется, что у вас не будет гонки в обработчике событий RunWorkerCompleted, так как он работает на потоке UI. Это всегда должно работать:[

] [
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
  var bgw = sender as BackgroundWorker;
  if (e.Cancelled || bgw.CancellationPending) {
    // etc..
  }
}
]
1
ответ дан 14 December 2019 в 19:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: