Многопоточность. Завершение потоков
Обновлен: Ноябрь 2007
Обычно завершение потока может произойти в двух случаях: если завершается выполнение контролирующей функции или если у потока нет разрешения на выполнение до конца. При использовании текстовым процессором потока для выполнения печати в фоновом режиме контролирующая функция завершается при успешном выполнении задания печати. Если необходимо отменить печать, сначала следует завершить поток для печати в фоновом режиме. В данном разделе рассматриваются оба эти случая, а также способы получения кода выхода из потока после его завершения.
Обычное завершение потока
Преждевременное завершение потока
Извлечение кода выхода из потока
Обычное завершение потока
Завершение рабочего потока выполняется просто: нужно просто завершить контролирующую функцию и возвратить значение, обозначающее причину завершения потока. Для этого можно использовать либо функцию AfxEndThread, либо оператор return. Обычно для обозначения успешного завершения используется значение "0", но можно выбрать и другое значение.
Завершение потока пользовательского интерфейса происходит так же просто: следует вызвать функцию PostQuitMessage (SDK для Windows) внутри потока пользовательского интерфейса. Единственный параметр, который использует функция PostQuitMessage — это код выхода из потока. Как и для рабочих потоков, успешное завершение, как правило, обозначается возвратом значения "0".
Преждевременное завершение потока
Преждевременное завершение потока выполняется почти так же просто. Следует вызвать функцию AfxEndThread в потоке. Передайте необходимый код выхода в качестве единственного параметра. Это приведет к остановке выполнения потока, отмене выделения памяти для потока в стеке, отключению всех библиотек DLL, используемых потоком, и удалению объекта потока из памяти.
Функцию AfxEndThread необходимо вызывать в завершаемом потоке. При необходимости завершить поток из другого потока, необходимо установить метод взаимодействия между этими потоками.
Извлечение кода выхода из потока
Чтобы получить код выхода из рабочего потока или потока пользовательского интерфейса, следует вызвать функцию GetExitCodeThread. Дополнительные сведения об этой функции см. SDK для Windows. Эта функция принимает дескриптор потока (который хранится в элементе данных m_hThread объектов CWinThread) и адрес параметра DWORD.
Если поток все еще активен, функция GetExitCodeThread передает значение STILL_ACTIVE по указанному адресу DWORD. В противном случае по этому адресу передается код выхода.
Для извлечения кода выхода из объектов CWinThread необходимо выполнить дополнительное действие. При завершении потока CWinThread объект потока по умолчанию удаляется. Это означает, что невозможно получить доступ к элементу данных m_hThread, поскольку объект CWinThread больше не существует. Чтобы избежать данной ситуации, выполните одно из следующих действий:
Задайте для элемента данных m_bAutoDelete значение FALSE. Это отменит автоматическое удаление объекта CWinThread после завершения потока. Теперь можно обращаться к элементу данных m_hThread и после завершения потока. При использовании этого метода следует вручную удалить объект CWinThread, поскольку платформа не выполнит удаление автоматически. Этот метод является предпочтительным.
Дескриптор потока следует хранить отдельно. После создания потока скопируйте его элемент данных m_hThread (с помощью функции ::DuplicateHandle) в другую переменную и обращайтесь к нему с помощью этой переменной. Этот метод позволяет узнать причину завершения потока, хотя объект при этом удаляется автоматически. Обратите внимание, что дескриптор необходимо скопировать до завершения потока. Наиболее безопасным способом для этого является передача CREATE_SUSPENDED в функцию AfxBeginThread, сохранение дескриптора, а затем возобновление потока с помощью функции ResumeThread.
Любой из этих способов позволяет определить причину завершения объекта CWinThread.
См. также
Основные понятия
Реализация многопоточности на языке C++ с помощью классов MFC