Приложение не выходит с 0 потоками

У нас есть настольное приложение WinForms, которое сильно многопоточно. 3 потока выполняются с Application.Run и множеством других фоновых рабочих потоков. Было сложно правильно закрыть все потоки, но я подумал, что наконец все понял.

Но когда мы фактически развернули приложение, пользователи начали ощущать, что приложение не закрывается. Существует System.Threading.Mutex, чтобы они не запускали приложение несколько раз, поэтому им нужно войти в диспетчер задач и убить старый, прежде чем они смогут запустить его снова.

Каждый поток получает Thread.Join до выхода из основного потока, и я добавил ведение журнала к каждому создаваемому потоку. Согласно журналу, каждый отдельный поток, который запускается, также завершается, и основной поток также завершается. Еще более странно то, что запуск SysInternals ProcessExplorer показывает, что все потоки исчезают при выходе из приложения. Как и в случае, есть 0 потоков (управляемых или неуправляемых), но процесс все еще выполняется.

Я не могу воспроизвести это ни на каких компьютерах разработчиков или в нашей тестовой среде, и пока я видел это только в Windows XP (не Vista, Windows 7 или любой другой Windows Server). Как процесс может продолжать работать с 0 потоками?

Редактировать:

Вот еще немного подробностей. В одном из циклов событий размещается библиотека взаимодействия Win32, которая использует COM-объект для взаимодействия с драйвером устройства. Я помещаю его в отдельный поток, потому что драйвер устройства чувствителен ко времени, и всякий раз, когда поток пользовательского интерфейса блокируется на значительное время (например, ожидает завершения вызова базы данных), он мешает работе драйвера устройства.

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


person Bryce Wagner    schedule 23.04.2010    source источник
comment
Проверьте это: blogs.msdn.com/oldnewthing/archive/2004 /07/23/192531.aspx   -  person Hans Passant    schedule 23.04.2010
comment
Это интересный сценарий, но он не соответствует тому, что происходит. Пользователь может полностью убить процесс через диспетчер задач, он просто никогда не завершается сам по себе. Мы оставили его включенным примерно на полчаса.   -  person Bryce Wagner    schedule 23.04.2010
comment
Почему вы уверены, что потоков ровно 0? Вы тестировали это с помощью отладчика? Даже диспетчер задач Windows XP может отображать количество потоков (однако вы должны явно добавить этот столбец на вкладку «Процессы» через Меню ›Вид› Выбрать столбцы ...). Сомневаюсь, что на самом деле потоков нет. Моя первая идея была бы в каком-то тупике в вашем процессе выхода / очистки.   -  person SergGr    schedule 23.04.2010


Ответы (3)


Когда вы создаете свои потоки, установите для них IsBackground = true. Когда ваш основной поток / приложение пользовательского интерфейса закрывается, все созданные потоки автоматически закрываются.

http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground.aspx

person David    schedule 23.04.2010

Возможно ли, что дочерние элементы ваших вызовов Application.Run не завершаются? Кроме того, что на самом деле вызывает завершение работы приложения - закрывается ли оно автоматически, когда все потоки завершаются (что автоматически означает, что вы написали код для этого), или это имитируется пользователем?

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

person SqlRyan    schedule 23.04.2010
comment
Вызов Application.Run завершается Application.Exit () в основном потоке. Я попытаюсь закрыть другие вызовы Application.Run (), прежде чем позволить основному потоку выйти. - person Bryce Wagner; 23.04.2010

Мы так и не выяснили основную программную причину, но проблема была вызвана конкретной версией драйвера, и обновление до нового драйвера устранило проблему.

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

person Bryce Wagner    schedule 22.10.2010