Завершение потока
Как и процесс, поток может быть завершен двумя способами - вызовом функции ExitThread() и обращением к функции TerminateThread(). Отличаются они друг от друга примерно тем же, что и функции ExitProcess() и TerminateProcess().
Функция ExitThread() используется для нормального завершения потока. Естественно, что она вызывается изнутри потока. Она описана в файле winbase.h следующим образом
VOID ExitThread(DWORD dwExitCode)
Параметр:
dwExitCode - код завершения этой функции.
Функцию TerminateThread() следует вызывать только в крайних случаях, когда поток завис, и ни на какие действия пользователя не реагирует. Функция вызывается из какого-либо внешнего (по отношению к завершаемому) потока, a ее аргументами являются хэндл завершаемого потока и двойное слово, в которое будет записан код завершения потока. Описание функции в файле winbase.h выглядит следующим образом,
BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode);
Параметры:
hThread – хэндл объекта завершаемого процесса.
dwExitCode – код завершения процесса.
Возвращаемое значение: если выполнение завершения произошло удачно, то TRUE, иначе - FALSE.
|
|
При завершении потока выполняются следующие действия.
1. Освобождаются или удаляются все занятые или созданные объекты. Действие является стандартным и ничего особенного собой не представляет.
2. Поток получает статус незанятого (signaled).
3. Код завершения процесса меняется со STILL_ACTIVE на указанный при вызове завершающей поток функции.
4. Уменьшается счетчик пользователей потока. Если пользователей потока больше не осталось, и поток является единственным потоком процесса, то завершается и процесс.
Момент выборки потока на выполнение осуществляется в соответствии с принятым в данной системе правилом предоставления процессорного времени и с учетом всех существующих в данный момент потоков и процессов.
По сравнению с Windows NT 4 в интерфейс Win32 API было введено, новое понятие волокон. Под волокном (fiber) понимается упрощенный поток, выполнение которого планируется в приложении вручную. Волокна выполняются в контексте потоков, в которых планируется их применение, и допускают полную их идентификацию с потоками.
Суть: потоки работают в режиме пользователя, но при системных вызовах переключаются в режим ядра. Из-за переключения в режим ядра и обратно, очень замедляется работа системы. Поэтому было введено понятие волокна.
В каждом потоке может быть запланировано несколько волокон. Волокна не дают никакого преимущества, по сравнению с корректно разработанным мультипоточным приложением, однако они упрощают перенос приложений, которые были специально разработаны для планирования собственных потоков.
|
|
Благодаря тому, что волокно допускает сходство с родительским потоком, оно разделяет вместе с потоком общую локальную память, а если волокно вызывает функции, которые, как правило, оказывают влияние на поток, в частности, ExitThread(), тогда эти функции выполняются и для потока. Например, если волокно обращается к функции ExitThread(), то в этом случае выполняется выход из потока, который создал это волокно. Однако у волокна отсутствует информация о состоянии, которая с ним связана и аналогична таковой, но связанной с потоком. Единственная информация о состоянии волокна сохраняется в его стеке, представляющем собой подмножество регистров, которые, как правило, сохраняются между вызовами функций, К этой же информации можно отнести и данные о волокне, предоставляемые, во время его создания.
Основное отличие между потоками и волокнами состоит в том, что волокна не планируются с вытеснением. Волокно должно планироваться в приложении путем переключения на него из другого волокна. Однако система все-таки планирует потоки, которые создают волокна, поэтому поток, который в настоящий момент выполняет волокно, может подлежать вытеснению. Волокно возобновляет свое выполнение, когда возобновляется выполнение его потока.
Перед планированием в приложении первого волокна для создания области, в которой сохраняется информация состояния волокна, вызывается функция ConvertThreadToFiber(). При этом поток превращается в выполняемое в настоящий момент волокно. К хранимой информации состояния этого волокна относятся также и данные, переданные функции ConvertThreadToFiber() в ее аргументе.
LPVOID ConvertThreadToFiber (LPVOID lpParameter)
Параметры:
lpParameter – единственная переменная, которая передается волокну. Волокно выбирает ее значение, используя функцию GetFiberData().
Возвращаемое значение: если выполнение завершения произошло удачно, то возвращается адрес волокна, иначе - NULL.
Для создания волокон в приложении применяется функция CreateFiber().
LPVOID CreateFiber (DWORD dwStackSize, LPFIBER_START_ROUTINE lpStartAdress, LPVOID lpParameter)
Параметры:
dwStackSize – размер стека волокна в байтах;
lpStartAdress – указатель на определяемую приложением функцию, которая выполняется волокном и задает начальный адрес волокна. Выполнение вновь созданного волокна не начинается до тех пор, пока другое волокно не вызовет функцию SwitchToFiber() по данному адресу.
lpParameter – единственная переменная, которая передается волокну. Волокно выбирает ее значение, используя функцию GetFiberData().
Возвращаемое значение: если выполнение завершения произошло удачно, то возвращается адрес волокна, иначе - NULL.
Начальный адрес, как правило, указывается для предоставляемой пользователем функции, называемой также функцией волокна (Fiber function). Эта функция обратного вызова имеет синтаксис
VOID WINAPI FiberFunc (PVOID lpParameter),
и воспринимает только один параметр, которым являются данные волокна, и не возвращает значение. Если же функция волокна возвращает значение, осуществляется выход из потока, выполняющей данное волокно. Для выполнения любого волокна, созданного с помощью функции CreateFiber(), в приложении применяется функция SwitchToFiber(), синтаксис которой следующий
VOID SwitchToFiber (LPVOID lpFiber),
Параметры:
lpFiber – адрес запускаемого волокна.
Возвращаемое значение: не имеет.
В функции SwitchToFiber() используется адрес волокна, созданного другим потоком, причем этот адрес получен другим потоком в результате обращения к CreateFiber(). После того как поток завершит выполнение своего волокна, она должна вызвать функцию DeleteFiber(), чтобы очистить данные, созданные для волокна. Синтаксис функции следующий:
VOID DeleteFiber (LPVOID lpFiber),
Параметры:
lpFiber – адрес удаляемого волокна.
Возвращаемое значение: не имеет.
Не следует удалять волокно, созданное другим потоком, поскольку это может привести к аварийному завершению другого потока.
|
|