'Это все работает нормально, пока я не попытаюсь закрыть приложение, когда, как и ожидалось, WaitForSingleObject продолжает ждать и не позволяет приложению закрыться должным образом.'
Любое приложение может закрыться, независимо от того, какие у него потокиделают.Если вы вызываете ExitProcess (0) из какого-либо потока в вашем приложении, приложение закроется, независимо от того, есть ли потоки, ожидающие INFINITE на каком-то API / sychro, спящие, работающие на другом процессоре, что угодно.ОС изменит состояние всех неиспользуемых команд, чтобы «никогда не запускаться снова», и использует свой межпроцессорный драйвер для жесткого прерывания любых других процессоров, которые фактически выполняют код вашего потока.Как только все потоки остановлены, ОС освобождает дескрипторы, сегменты и т. Д., И ваше приложение больше не существует.
Проблемы возникают, когда разработчики пытаются «аккуратно» закрыть застрявшие потоки, как у вас, когда приложениезакрытие.Итак ...
У вас есть TThread.WaitFor или аналогичный в обработчике OnClose / OnCloseQuery, FormDestroy или деструкторе?Если у вас есть и у вас нет веских причин гарантировать, что поток завершен, просто закомментируйте его!
Это позволяет закрывать основную форму, и, таким образом, ваш код, наконец, достигает ExitProcess (), который он пыталсячтобы получить, так как вы нажали на кнопку красного креста
Конечно, вы могли бы просто вызвать ExitProcess () самостоятельно, но это может привести к утечке ресурсов в других процессах - например, соединения с базой данных.
'Ошибки 216/217 при закрытии, если я не остановлю потоки'.Это часто происходит потому, что разработчики следовали ошибочным «неудачным» примерам потоков Delphi и общаются с потоками, напрямую обмениваясь данными между полями вторичных потоков и полями основных потоков (например, TThread.synchronize).Это просто отстой, и он одержим проблемами, даже при запуске приложения, не говоря уже о закрытии, когда форма уничтожена, и поток пытается записать в нее, или поток был уничтожен, и форма основного потокапытаясь не вызывать методы на нем.Гораздо безопаснее общаться асинхронно с потоками с помощью объектов очередей / PostMessaging, которые переживают их обоих, например.объекты, созданные в потоке / форме и освобожденные в форме / потоке или с помощью (потокобезопасного) пула объектов, созданных в разделе инициализации.Затем формы можно безопасно закрывать / освобождать, в то время как связанные потоки могут продолжать бессмысленно заполнять объекты для обработки до тех пор, пока не закроется основная форма, не будет достигнут ExitProcess () и ОС не уничтожит потоки.
'Дескриптор моей формы недопустим, посколькуон закрылся, но моя ветка пытается отправить ему сообщение ».Если PostMessage исключает, выйдите из вашей темы.Лучший способ аналогичен подходу, описанному выше - отправлять сообщения только в окно, которое переживает все формы.Создайте его в разделе инициализации с помощью тривиального WndProc, который обрабатывает только один постоянный номер сообщения, который все потоки используют для публикации.Вы можете использовать wParam для передачи экземпляра TwinControl , с которым пытается связаться поток (обычно это переменная формы), в то время как lParam передает передаваемый объект.Когда он получает сообщение из потока, WndProc вызывает 'Peform' на переданном TwinControl, и TwinControl получает объект comms в обработчике сообщений.Простое глобальное логическое значение, AppClosing, скажем, может остановить WndProc, вызывающий Peform () для TwinControls, которые освобождаются во время завершения работы.Этот подход также позволяет избежать проблем, возникающих, когда ОС воссоздает ваше окно формы с другим дескриптором - дескриптор формы Delphi не используется, и Windows не будет повторно создавать / изменять дескриптор простой формы, созданной при инициализации.
У меня естьследовал этим подходам в течение десятилетий и не испытывал никаких проблем с завершением работы, даже если приложения с десятками потоков перебрасывали объекты в очереди.
Rgds, Martin