Волокна

Завершение потока

Как и процесс, поток может быть завершен двумя способами - вызо­вом функции 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 – адрес удаляемого волокна.

Возвращаемое значение: не имеет.

Не следует удалять волокно, созданное другим потоком, поскольку это может привести к аварийному завершению другого потока.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: