Поток не прерывается при закрытии приложения

У меня есть приложение, которое выполняет некоторые фоновые задачи (прослушивание и чтение сети) в отдельном файле Thread. Однако кажется, что поток не прерывается/не прерывается, когда я закрываю приложение (нажмите кнопку «x» в заголовке). Это потому, что основной подпрограммой Thread является while(true) {...} ? Какое решение здесь? Я искал некоторый флаг «прерывания» для потока в качестве условия для цикла «пока», но не нашел.


person migajek    schedule 17.05.2010    source источник


Ответы (5)


Самый простой способ — установить свойство IsBackground. потока в true. Это предотвратит сохранение приложения открытым. Приложение завершается, когда завершаются все нефоновые потоки.

Более контролируемый способ остановить поток — отправить ему сообщение для корректного закрытия и убедиться, что он завершен, прежде чем разрешить завершение основного потока.

Я бы не рекомендовал использовать метод Thread.Abort. Это имеет ряд проблем, одна из которых заключается в том, что не гарантируется завершение потока. Из документации:

Вызов этого метода обычно завершает поток.

Акцент мой.

person Mark Byers    schedule 17.05.2010
comment
+1 к способу сообщения. while (stayAlive) вместо true намного чище, даже если для очистки цикла может потребоваться несколько дополнительных секунд. - person user7116; 18.05.2010

Вы всегда можете форсировать проблему:

class Program
{
    public static void Main()
    {
        // ... do stuff
        Environment.Exit(Environment.ExitCode);
    }
}

Лучший подход — установить для свойства Thread.IsBackground значение true, как уже упоминал Марк.

person csharptest.net    schedule 17.05.2010

Вы можете улучшить цикл while(true) до

void DoWork() {
    while(!ShouldIQuitManualResetEvent.WaitOne(0)) {
      // do something
    }
    IDidQuitManualResetEvent.Set()
}

Чуть более изящный, короткий от имени идентификатора.

person Hans Passant    schedule 17.05.2010

Ну, вместо while(true), может быть, вам стоит:

while(appIsRunning)
{
}

И, на заключительном мероприятии для вашей формы,

appIsRunning = false;
thread.Join(2000);

где последняя строка предназначена только для того, чтобы убедиться, что вы ждете, пока поток завершится чисто. Есть много других способов принудительно завершить цепочку, но проблема заключается именно в этом: вы не хотите форсировать события, вы хотите, чтобы они происходили как можно более естественно.

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

person Bruno Brant    schedule 17.05.2010
comment
Да, но не забудьте использовать volatile или lock или какой-либо другой метод синхронизации. - person Mark Byers; 18.05.2010
comment
@Mark: здесь может быть совершенно неправильно, но поскольку дочерний поток только читает, а основной поток только пишет, есть ли вероятность ошибки? - person Bruno Brant; 18.05.2010
comment
Без синхронизации не гарантируется, что изменение appIsRunning из одного потока будет видно в другом потоке. Вы можете прочитать больше здесь: timl.net/2009/03/volatile-memory.html< /а> - person Mark Byers; 18.05.2010

Вы можете начать свою тему как:

ThreadPool.QueueUserWorkItem(DoStuff, input)

И это будет прервано автоматически с закрытием приложения.

person darja    schedule 17.05.2010