10.4. Менеджер потоков

Вверх  Предыдущий  Следующий

Подобно тому, как куча реализована с использованием менеджера кучи, а управление widestring выполняется менеджером widestring, потоки выполняются с использованием менеджера потоков. Это означает, что имеется запись, которая содержит поля процедурного типа для всех возможных используемых функций в потоковых подпрограммах. Потоковые подпрограммы фактически используют эти поля работы.

Потоковые подпрограммы устанавливают свой менеджер потоков для каждой системы. На Windows обычные подпрограммы Windows используются для выполнения функций в менеджере потоков. На Linux и подобных системах менеджер потоков ничего не делает: он будет генерировать ошибку, если используются потоковые подпрограммы. Смысл этого в том, что подпрограммы управления потоками локализованы в библиотеке С. Реализация менеджера потоков в системе привела бы к необходимости сделать RTL зависимой от библиотеки С, что нежелательно. Чтобы избежать этой зависимости от библиотеки С, Менеджер Потоков реализован как отдельный модуль (cthreads). Код инициализации этого модуля устанавливает менеджер потоков для управления записями потоков, которые используются подпрограммами C (pthreads).

Запись менеджера потоков может быть восстановлена и установлена также, как запись менеджера кучи. На текущий момент запись выгладит следующим образом:

TThreadManager = Record
  InitManager             : Function : Boolean;
  DoneManager             : Function : Boolean;
  BeginThread             : TBeginThreadHandler;
  EndThread               : TEndThreadHandler;
  SuspendThread           : TThreadHandler;
  ResumeThread           : TThreadHandler;
  KillThread             : TThreadHandler;
  ThreadSwitch           : TThreadSwitchHandler;
  WaitForThreadTerminate : TWaitForThreadTerminateHandler;
  ThreadSetPriority       : TThreadSetPriorityHandler;
  ThreadGetPriority       : TThreadGetPriorityHandler;
  GetCurrentThreadId     : TGetCurrentThreadIdHandler;
  InitCriticalSection     : TCriticalSectionHandler;
  DoneCriticalSection     : TCriticalSectionHandler;
  EnterCriticalSection   : TCriticalSectionHandler;
  LeaveCriticalSection   : TCriticalSectionHandler;
  InitThreadVar           : TInitThreadVarHandler;
  RelocateThreadVar       : TRelocateThreadVarHandler;
  AllocateThreadVars     : TAllocateThreadVarsHandler;
  ReleaseThreadVars       : TReleaseThreadVarsHandler;
end;

Значение большинства этих функций должно быть понятным из описания в предыдущих разделах.

InitManager и DoneManager вызываются, когда менеджер потоков устанавливается (InitManager) или когда он удаляется (DoneManager). Они могут использоваться для инициализации менеджера потоков или для освобождения памяти, когда это необходимо. Если какая-либо из этих функций возвращает False, то операция заканчивается неудачей.

Имеются некоторые специальные элементы в записи, связанные с переменными менеджера потоков:

InitThreadVar вызывается, когда потоковая переменная должна быть инициализирована. Она имеет тип:

TInitThreadVarHandler = Procedure(var offset: dword; size: dword);

Параметр offset указывает на смещение в блоке потоковых переменных: все потоковые переменные размещены в одном блоке, одна за одной. Параметр size указывает размер потоковой переменной. Эта функция вызывается один раз для всех потоковых переменных в программе.

RelocateThreadVar вызывается каждый раз при запуске потока, один раз для каждого потока. Она имеет тип:

TRelocateThreadVarHandler = Function(offset : dword) : pointer;

Она должна возвращать новое местоположение для потоковой переменной.

AllocateThreadVars вызывается, когда блок должен быть выделен для всех потоковых переменных для нового потока. Это простая процедура без параметров. Общий размер потоковых переменных записывается компилятором в глобальной переменной threadvarblocksize. Менеджер кучи не может быть использован в этой процедуре: менеджер кучи сам использует потоковые переменные, которые ещё не были выделены.

ReleaseThreadVars – эта процедура (без параметров) вызывается при завершении потока, и вся выделенная память должна быть снова освобождена.