Прерывание фоновой работы

Недавно я пытался использовать backgroundworker вместо «классических» потоков, и я понимаю, что это вызывает, по крайней мере для меня, больше проблем, чем решений. У меня есть фоновый рабочий, выполняющий синхронное чтение (в данном случае из serialPort) и блокирующийся примерно на 30 секунд в 1 строке кода, тогда ожидание отмены не является решением. Я вижу, что если приложение закрывается в этот момент (либо с помощью перекрестной кнопки, либо с помощью Application.Exit()), процесс сохраняет зомби навсегда.

Мне нужен способ принудительно прервать или убить фоновый поток.


person MazarD    schedule 05.03.2009    source источник


Ответы (5)


Я не очень уверен в том, чего вы пытаетесь достичь, но, возможно, SerialPort.DataReceived является лучшим решением?

Если вы уже разбираетесь в использовании потоков, я не вижу смысла в использовании BackgroundWorker. Он предназначен для людей, которые вообще не разбираются в тредах.

Кроме того, мне не нравится идея прерывания темы. Это кажется опасным, и многопоточным приложениям больше не нужно рисковать.

person DonkeyMaster    schedule 05.03.2009
comment
Я обнаружил, что SerialPort.DataReceived немного сбивает с толку в CF, не знаю, лучше ли внедрение в FF. CF использует больше потоков, чем вы ожидаете, так что будьте осторожны. - person Quibblesome; 05.03.2009
comment
Почти поддался искушению -1 за комментарий о BackgroundWorker; он предназначен для обеспечения соблюдения некоторых стандартов и автоматического маршалирования событий в поток пользовательского интерфейса, что является веским основанием для его использования; непонимание многопоточности вызовет проблемы независимо от того, каким путем вы пойдете. - person Alex Paven; 12.10.2010
comment
Если нет более простого способа синхронизации с потоком пользовательского интерфейса из обычного потока... - person Glimpse; 13.06.2014

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

var backgroundWorker = new BackgroundWorker(){WorkerSupportsCancellation = true};

backgroundWorker.DoWork += (sender, args) =>
         {                 
                 var thisWorker = sender as BackgroundWorker;
                 var _child = new Thread(() =>
                                               {
                                                   //..Do Some Code

                                               });
                 _child .Start();
                 while (_child.IsAlive)
                 {
                     if (thisWorker.CancellationPending)
                     {
                         _child.Abort();
                         args.Cancel = true;
                     }
                     Thread.SpinWait(1);
                 }                 
         };

 backgroundWorker.RunWorkerAsync(parameter);
 //..Do Something...
backgroundWorker.CancelAsync();

Поскольку фоновый рабочий процесс является частью пула потоков, мы не хотим его прерывать. Но мы можем запустить внутренний поток, в котором мы можем разрешить прерывание. Затем backgroundWorker в основном работает до тех пор, пока либо дочерний поток не завершится, либо пока мы не сообщим ему о завершении процесса. Затем фоновый рабочий поток может вернуться в пул чтения. Обычно я оборачиваю это во вспомогательный класс и передаю метод делегата, который я хочу, чтобы фоновый поток выполнялся в качестве параметра, и запускал его в дочернем потоке.

Пожалуйста, кто-нибудь, дайте мне знать, если я бьюсь головой о стену, но, похоже, это работает нормально.

person Rob    schedule 07.04.2010
comment
Это интересное решение, но, на мой взгляд, было бы эффективнее создать класс, обертывающий объект Thread и взаимодействие с ним, а не использовать BackgroundWorker в качестве посредника. Насколько я понимаю, причин для этого действительно нет. - person René; 04.01.2013

Процесс не должен стать зомби, поскольку поток BackgroundWorker помечен как «фоновый» и должен завершаться при закрытии пользовательского интерфейса.

person uli78    schedule 06.07.2009
comment
Это верно, поскольку BW использует класс ThreadPool за кулисами. - person Teoman shipahi; 21.07.2014

Я не думаю, что BackgroundWorker поддерживает уничтожение потока. Отмена операции должна выполняться в методе, выполняющем задание. В вашем случае я думаю, что обычная нить будет лучшим вариантом.

person Rune Grimstad    schedule 05.03.2009

Вы можете попробовать это:

            backgroundworker.Dispose();
            backgroundworker = null;
            GC.Collect(); //this helps cleans up ram
person Earlee    schedule 17.08.2015