Как отменить асинхронный вызов? - PullRequest
18 голосов
/ 13 ноября 2009

Как отменить асинхронный вызов? .NET APM, кажется, не поддерживает эту операцию.

В моем коде есть следующий цикл, который порождает несколько потоков в ThreadPool. Когда я нажимаю кнопку на своем пользовательском интерфейсе, я хочу, чтобы эти потоки (или асинхронные вызовы) заканчивались.

foreach (var sku in skus)
{
    loadSku.BeginInvoke(...
}

Есть ли какое-нибудь элегантное решение, кроме создания глобального "флага отмены" и наличия асинхронных методов для его поиска?

Ответы [ 3 ]

18 голосов
/ 13 ноября 2009

«Флаг отмены» - это способ сделать это, хотя и не глобальный, обязательно. Неизбежным моментом является то, что вам нужен какой-то способ сообщить потоку, что он должен прекратить то, что он делает.

В случае BeginInvoke это трудно сделать с чем-либо, кроме глобального флага, потому что работа выполняется в пуле потоков, и вы не знаете, какой поток. У вас есть несколько вариантов (в порядке предпочтения):

  1. Используйте BackgroundWorker вместо BeginInvoke. Это имеет функциональность отмены, запеченная в . Это имеет и другие преимущества, такие как мониторинг хода выполнения и обратные вызовы "Работа завершена" . Это также приятно обрабатывает исключения .
  2. Используйте ThreadPool.QueueUserWorkItem, передавая объект как состояние, которое имеет метод Cancel(), который устанавливает флаг Cancelled, который может проверить исполняемый код. Конечно, вам нужно сохранить ссылку на объект состояния, чтобы вы могли вызывать Cancel() на нем (это то, что BackgroundWorker делает для вас - у вас есть компонент в вашей форме. (Спасибо Fredrik) за напоминание об этом).
  3. Создайте свой собственный ThreadStart делегат, передав объект состояния как с опцией 2.
1 голос
/ 13 ноября 2009

Если вы ищете метод TerminateAsnyc, вы его не найдете. Следовательно, нет, вероятно, нет элегантного способа использования Control.BeginInvoke / EndInvoke. Таким образом, я бы поставил логический флаг в потоке пользовательского интерфейса, и чтобы выполняемый делегат периодически проверял этот флаг во время его выполнения.

Однако вы можете проверить использование фоновых рабочих потоков.

0 голосов
/ 13 ноября 2009

Определенно есть и другие решения, хотя я не знаю, что бы я назвал их «элегантными».

Вы можете вызвать прерывание или прерывание в потоке, но это может иметь некоторые отрицательные побочные эффекты. Лично для этого я предпочитаю использовать BackgroundWorker, если это возможно. Он имеет функцию отмены, но он похож на то, что вы упомянули - флаг bool в классе, который вы должны периодически проверять в исполняемом коде (по крайней мере, это не глобальный флаг). Этот пост об остановке тем в .NET немного устарел, но в нем рассматриваются некоторые подводные камни других опций, которые я упоминал выше.

...