10.2. Программирование потоков

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

Для запуска нового потока должна использоваться функция BeginThread. Она имеет один обязательный параметр: функцию, которая будет выполнена в новом потоке. Результатом функции является выход результата потока. В потоковую функцию может быть передан указатель, который может быть использован для доступа к данным инициализации: программист должен убедиться, что данные будут доступны из потока и не выходят из области видимости потока раньше, чем поток обратится к ним.

Type
  TThreadFunc = function(parameter : pointer) : ptrint;
function BeginThread(sa : Pointer;
                    stacksize : SizeUInt;
                    ThreadFunction : tthreadfunc;
                    p : pointer;
                    creationFlags : dword;
                    var ThreadId : TThreadID) : TThreadID;

Это полная форма функции, возможен также вызов функции в упрощённой форме:

function BeginThread(ThreadFunction : tthreadfunc) : TThreadID;
function BeginThread(ThreadFunction : tthreadfunc;p : pointer) : TthreadID;
function BeginThread(ThreadFunction : tthreadfunc;p : pointer;var ThreadId : TThreadID) : TthreadID;
function BeginThread(ThreadFunction : tthreadfunc;p : pointer;var ThreadId : TThreadID;const stacksize: SizeUInt) : TthreadID;

Параметры имеют следующие значения:

ThreadFunction – это функция, которая должна быть выполнена в потоке.

р – если имеется, то указатель р будет помещён в потоковую функцию, когда она начнёт выполняться. Если р не указан, то помещается Nil.

ThreadID – если ThreadID указан, то в него будет записан ID потока.

stacksize – если указан, то этот параметр определяет размер стека, используемого потоком.

sa – сигнализирует о действии. Имеет значение только для LINUX.

creationflags – это специфический для системы флаг создания. Имеет значение только для windows и OS/2.

Вновь запущенный поток будет работать до тех пор, пока не будет выполнен выход из функции ThreadFunction, или пока не будет явно вызвана функция EndThread:

procedure EndThread(ExitCode : DWord);
procedure EndThread;

exitcode может быть проанализирован код, который запустил поток.

Ниже приведён небольшой пример потоковой программы:

{$mode objfpc}
uses sysutils {$ifdef unix},cthreads{$endif} ;
 
const threadcount = 100;
stringlen = 10000;
 
var
finished : longint;
 
threadvar
thri : ptrint;
 
function f(p : pointer) : ptrint;
var s : ansistring;
begin
  Writeln('thread ',longint(p),' started');
  thri:=0;
  while (thri<stringlen) do
    begin
    s:=s+'1';
    inc(thri);
    end;
  Writeln('thread ',longint(p),' finished');
  InterLockedIncrement(finished);
  f:=0;
end;
var i : longint;
 
begin
  finished:=0;
  for i:=1 to threadcount do
    BeginThread(@f,pointer(i));
  while finished<threadcount do ;
  Writeln(finished);
end.

InterLockedIncrement – это потокобезопасная версия стандартной функции Inc.

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

function SuspendThread(threadHandle: TThreadID): dword;
function ResumeThread(threadHandle: TThreadID): dword;
function KillThread(threadHandle: TThreadID): dword;
function WaitForThreadTerminate(threadHandle: TThreadID; TimeoutMs : longint): dword;
function ThreadSetPriority(threadHandle: TThreadID;Prio: longint): boolean;
function ThreadGetPriority(threadHandle: TThreadID): Integer;
function GetCurrentThreadId: dword;
procedure ThreadSwitch;

Смысл этих функций должен быть понятен:

SuspendThread – приостанавливает выполнение потока.

ResumeThread – возобновляет выполнение приостановленного потока.

KillThread – уничтожает поток: поток удаляется из памяти.

WaitForThreadTerminate – ожидает завершения потока. Функция возвращает результат, когда выполнение потока завершено или время ожидания истекло.

ThreadSetPriority – задаёт приоритет выполнения потока. Этот вызов не всегда допустим: ваш процесс может не иметь для этого достаточных прав.

ThreadGetPriority – возвращает текущий приоритет выполнения потока.

GetCurrentThreadId – возвращает идентификатор текущего потока.

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