Завершение потока
Завершение потока можно выполнить четырьмя способами:
- Функция потока возвращается.(Это настоятельно рекомендуется.)
- Поток убивает себя, вызывая функцию ExitThread.(Избегайте этого метода.)
- Поток в том же процессе или в другом вызывает функцию TerminateThread.(Избегайте этого метода.)
- Процесс, содержащий поток, завершается.(Избегайте этого метода.)
Функция потока возвращает
Вы должны всегда проектировать свои функции потока так, чтобы они возвращались, когда вы хотите, чтобы поток завершился.Это единственный способ гарантировать, что все ресурсы вашего потока очищены должным образом.
Возврат вашей функции потока гарантирует следующее:
- Все объекты C ++, созданные в вашей функции потока, будутбыть должным образом уничтожены через их деструкторы.
- Операционная система должным образом освободит память, используемую стеком потока.
- Система установит код выхода потока (поддерживаемый в объекте ядра потока) равнымвозвращаемое значение функции вашего потока.
- Система уменьшит счетчик использования объекта ядра потока.
Функция ExitThread
Youможет заставить ваш поток завершиться, вызвав его ExitThread:
VOID ExitThread (DWORD dwExitCode);
Эта функция завершает поток и заставляет операционную систему очищать все ресурсы операционной системы, которыебыли использованы потоком.Однако ваши ресурсы C / C ++ (такие как объекты класса C ++) не будут уничтожены.По этой причине гораздо лучше просто вернуться из своей функции потока, а не вызывать ExitThread самостоятельно.
Конечно, вы используете параметр dwExitCode в ExitThread, чтобы указать системе, на что установить код выхода потока.Функция ExitThread не возвращает значение, потому что поток завершен и не может выполнять больше кода.
Примечание Рекомендуемый способ завершить поток - просто вернуть его функцию потока (как описано в предыдущем разделе).).Однако, если вы используете метод, описанный в этом разделе, помните, что функция ExitThread - это функция Windows, которая убивает поток.Если вы пишете код на C / C ++, вы никогда не должны вызывать ExitThread.Вместо этого вы должны использовать библиотечную функцию C ++ _endthreadex.Если вы не используете компилятор Microsoft C ++, у вашего поставщика компилятора будет собственная альтернатива ExitThread.Какой бы ни была эта альтернатива, вы должны ее использовать.
Функция TerminateThread
Вызов TerminateThread также убивает поток:
BOOL TerminateThread (HANDLEhThread, DWORD dwExitCode);
В отличие от ExitThread, который всегда убивает вызывающий поток, TerminateThread может уничтожить любой поток.Параметр hThread идентифицирует дескриптор потока, который должен быть завершен.Когда поток завершается, его код выхода становится значением, которое вы передали в качестве параметра dwExitCode.Кроме того, у объекта ядра потока уменьшен счет использования.
Примечание. Функция TerminateThread является асинхронной.Таким образом, он сообщает системе, что вы хотите, чтобы поток завершился, но поток не гарантированно будет уничтожен к моменту возврата функции.Если вам нужно точно знать, что поток завершен, вы можете вызвать WaitForSingleObject или аналогичную функцию, передавая дескриптор потока.
Хорошо спроектированное приложение никогда не использует эту функцию, потому что потокпрекращено не получает уведомления о том, что он умирает.Поток не может очиститься должным образом и не может предотвратить себя.
Примечание. Когда поток умирает, возвращая или вызывая ExitThread, стек для потока уничтожается.Однако, если используется TerminateThread, система не уничтожает стек потока до тех пор, пока процесс, которому принадлежит этот поток, не завершится.Microsoft намеренно реализовала TerminateThread таким образом.Если бы другие все еще выполняющиеся потоки ссылались на значения в стеке принудительно уничтоженного потока, эти другие потоки вызовут нарушения прав доступа.Оставив стек уничтоженного потока в памяти, другие потоки могут продолжать нормально работать.
Кроме того, библиотеки динамических ссылок (DLL) обычно получают уведомления, когда поток завершается.Однако, если поток принудительно уничтожен с помощью TerminateThread, библиотеки DLL не получают это уведомление, что может помешать правильной очистке.
Когда поток завершается
Следующие действияпроисходит, когда поток завершается:
Все дескрипторы объекта пользователя, принадлежащие потоку, освобождаются.В Windows большинство объектов принадлежит процессу, содержащему поток, который создает объекты.Однако поток владеет двумя объектами User: окнами и хуками.Когда поток умирает, система автоматически уничтожает все окна и удаляет все хуки, которые были созданы или установлены потоком.Другие объекты уничтожаются только после завершения процесса-владельца.
Код выхода потока изменяется с STILL_ACTIVE на код, переданный в ExitThread или TerminateThread.
Состояние объекта ядра потока становится сигнальным.
Если поток является последним активным потоком в процессе, система считает, что процесс также завершен.
Счетчик использования объекта ядра потока уменьшается на 1.
Когдапоток завершается, связанный с ним объект ядра потока не освобождается автоматически до тех пор, пока не будут закрыты все оставшиеся ссылки на объект.
Как только поток перестает работать, в потоке больше не остается никаких других потоков.Система может делать с ручкой потока.Однако эти другие потоки могут вызывать GetExitCodeThread, чтобы проверить, завершился ли поток, идентифицированный hThread, и, если он имеет, определить свой код выхода:
BOOL GetExitCodeThread (HANDLE hThread, PDWORD pdwExitCode);
Значение кода выхода возвращается в DWORD, на который указывает pdwExitCode.Если поток не завершился при вызове GetExitCodeThread, функция заполняет DWORD идентификатором STILL_ACTIVE (определенным как 0x103).Если функция выполнена успешно, возвращается TRUE.