none
Как убить поток в C#

    Frage

  • Написал небольшую программу на C#.

    Идёт работа с веб-сервисом в отдельном потоке, который запускаю кнопкой из Главной формы.

    Для создания фонового потока использую класс BackgroundWorker, так как он позволяет по завершении отобразить результаты в Главном окне.

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

    Если кто не в курсе, то обращение к веб-сервису - это одна команда (вызов метода). Она и висит.

    Стандартные методы завершения успеха не имеют. 

    Пробую, например, так:

    private void button1_Click(object sender, EventArgs e)
            {
                // Cancel the asynchronous operation.
                this.bgrWorker1.CancelAsync(); // мягкое завершение
                LoadThread.Abort();            // жёсткое завершение (LoadThread - ссылка на поток)
    
                while (this.bgrWorker1.IsBusy)
                {
                    Thread.Sleep(10);  
                    Application.DoEvents();
                }
    
                MessageBox.Show("Поток закрылся");
            }

    Dienstag, 27. November 2012 10:35

Antworten

  • Чтобы уничтожить поток необходимо, чтобы в потоке корректно были уничтожены все объекты. Обычно с этим не возникает проблем, если программа написана на одном из языков .NET, из-за механизмов "уборки мусора". В Вашем же случае, наверняка в сервисе, к которому обращается поток, создаются объекты, написанные, не на .NET, а на основе COM. А в COM нет автоматизации при уничтожении/уборке мусора. И если программисты веб-сервиса забыли написать функционал уничтожения COM объектов, то закрыть поток программно Вы не сможете, так как .NET не справляется с задачей автоматического уничтожения созданных объектов внутри потока. В случае, если веб-сервис нельзя переписать, по-моему, нет другого выхода, кроме как закрывать программу. Как вариант, можно создать искусственную "утечку памяти", создавая потоки обращения к веб-сервису каждый раз заново, когда это нужно, в расчете на то, что программу рано или поздно закроют, и все потоки будут уничтожены. 
    Freitag, 30. November 2012 12:18
  • Привет.

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

    Cancel у BackgroundWorker просто выставляет соотвествующее свойство и вы должны предусмотреть проверку его в самом DoWork методе, но т.к. подключение от вас не зависит - то вы тут врядли что сможете сделать.

    Принудительная остановка потока через Abort должна убить поток, но не факт что ресурсы, которыми владел этот поток, поэтому использовать его не желательно.

    Как я уже написал - самое верное это дожидаться таймаута и скорей всего вы можете регулировать его длительность.


    Для связи [mail]

    Montag, 3. Dezember 2012 08:10

Alle Antworten

  • Наверное немного (или много) не хороший способ, но вот что я надумал:

    В методе где работает BackWorker можно создать поток, и имея на него ссылку сделать ему "Abort".

    А в воркере ожидать пока он завершится.

    Тот же делегат создать,
    в его методе взять Thread.CurrentThread - он и будет ссылкой на поток.

    Ну а там
    BeginInvoke
    EndInvoke

    Понятия не имею сработает ли, но вот

    //
    ПС.
    НУ или просто в самом воркере и взять Thread.CurrentThread в самом начале того асинхронного метода
    А то я тут нагородил.




    • Bearbeitet INFEL8 Dienstag, 27. November 2012 12:07
    Dienstag, 27. November 2012 12:02
  • У меня 
     LoadThread и есть Thread.CurrentThread из воркера
    Dienstag, 27. November 2012 12:24
  • А, и это не срабатывает?
    ну тогда не знаю.
    У меня тоже подобная проблема бывает, но я не пытался прервать, всё равно через таймаут само прервётся.
    У меня там производительность в этом месте не важна была тогда.

    Я бы предложил обернуть вызов той команды в поток, и с ним то же самое проделать,
    но это вроде как то же самое.
    А то и вообще не то.
    • Bearbeitet INFEL8 Dienstag, 27. November 2012 12:43
    Dienstag, 27. November 2012 12:33
  • Чтобы уничтожить поток необходимо, чтобы в потоке корректно были уничтожены все объекты. Обычно с этим не возникает проблем, если программа написана на одном из языков .NET, из-за механизмов "уборки мусора". В Вашем же случае, наверняка в сервисе, к которому обращается поток, создаются объекты, написанные, не на .NET, а на основе COM. А в COM нет автоматизации при уничтожении/уборке мусора. И если программисты веб-сервиса забыли написать функционал уничтожения COM объектов, то закрыть поток программно Вы не сможете, так как .NET не справляется с задачей автоматического уничтожения созданных объектов внутри потока. В случае, если веб-сервис нельзя переписать, по-моему, нет другого выхода, кроме как закрывать программу. Как вариант, можно создать искусственную "утечку памяти", создавая потоки обращения к веб-сервису каждый раз заново, когда это нужно, в расчете на то, что программу рано или поздно закроют, и все потоки будут уничтожены. 
    Freitag, 30. November 2012 12:18
  • Привет.

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

    Cancel у BackgroundWorker просто выставляет соотвествующее свойство и вы должны предусмотреть проверку его в самом DoWork методе, но т.к. подключение от вас не зависит - то вы тут врядли что сможете сделать.

    Принудительная остановка потока через Abort должна убить поток, но не факт что ресурсы, которыми владел этот поток, поэтому использовать его не желательно.

    Как я уже написал - самое верное это дожидаться таймаута и скорей всего вы можете регулировать его длительность.


    Для связи [mail]

    Montag, 3. Dezember 2012 08:10