BeginThread, функция
Синтаксис
function BeginThread(SecurityAttributes: Pointer; StackSize: LongWord;
ThreadFunc: TThreadTunc; Parameter: Pointer; CreationFlags: LongWord;
var Threadld: LongWord): Integer;
Описание
Функция BeginThread вызывается для запуска потока в многопоточ-ном приложении
и обращается к функции Windows API CreateThread. которая начинает новый поток
и, в свою очередь, вызывает функця потока (ThreadFunc) в контексте нового потока.
Когда функция поток заканчивает работу, поток завершается. За дополнительной
информ цией об атрибутах безопасности и флагах обратитесь к документации Windows
API по функции CreateThread.
BeginThread возвращает дескриптор нового потока или ноль, если Windows не создаст
поток. BeginThread - это настоящая функция.
Ошибки
Советы и приемы
- Следует использовать функцию BeginThread вместо функции CreateThread
Windows API, т.к. BeginThread выставляет глобальную переменную IsMuItiTread
в истину. BeginThread также определяет параметры ThreadFunc и ThreadID в
стиле языка Паскаль.
- Функция потока должна перехватывать и обрабатывать все исключительные
ситуации. Если функция потока вызывает исключительную ситуацию, которую
не может обработать, ее перехватывает BeginThread и прерывает программу.
- Как и для любого другого ресурса, следует вызвать CloseHandle после окончания
работы потока, чтобы Windows освободил все связанные с ним ресурсы. Если
вы создадите поток в приостановленном состоянии и затем закроете его, ни
разу не запустив, в Delphi произойдет небольшая утечка памяти. Чтобы предотвратит:
утечку, всегда запускайте поток до того, как его закроете.
Пример
В следующем примере показан фоновый поток, который вычисляв множество Мандельброта и рисует его
изображение в растре. Фоновый поток уведомляет основной поток программы о том, что формирование
изображения закончено, и оно может быть выведено на экран.
В фоновом потоке используется свойство Scanline, т. к. это обеспечивает быстрый и удобный доступ к
данным растра без привлечения Windows АРI. Если потоку требуются функции Windows GDI,
следует использовать метод TThread Synchronize из модуля Classes.
const // Фоновый поток посылает это сообщение основному.
Wm_Finished = Wm_User;
type
TThreadInfo = class;
TWmFinished = packed record
Msg: Cardinal;
Aborted: Boolean;
Bitmap: TBitmap;
Rasult: LongInt;
end;
// Каждому потоку передается объект Threadlnfo. Обьект создает
// растровое изображение, в котором создается множество Мандельбрста
// и флаг, который поток периодически проверяет, чтобы определить
// необходимость заранее прервать свою работу.
TThreadlnfo = class
private
fBitmap: TBitmap;
fAborted: Boolean;
Public
constructor Create(Width, Height: Integer);
destructor Destroy; override;
procedure Abort;
property Bitmap: TBitmap read fBitmap;
property Aborted: Boolean read fAborted;
end;
// Число итераций устанавливаем равным 360, чтобы было легче
// преобразовать количество итераций в значение Hue (цветовое
// смещение) в цветовой схеме HSV.
const
Maxlterations = 360;
// Смотрите пример для процедуры Exit, чтобы найти функцию
// Computelterations.
// Эти начальные точки смотрятся неплохо. Вы можете их изменить,
// если хотите увидеть что-нибудь другое.
const
XOffset = -0.03;
YOffset = 0.78;
Zoom = 450000.0;
Background = clBlack;
// Растр использует 24-разрядный формат пикселов, так что
// каждый пиксел зачинает три байта. Массив TRgb облегчает доступ
// к красной, зеленой и синей компонентам цвета строки изображения.
type
TRgb = array[0..2] of Byte;
PRgb = ^TRgb;
function MandelbrotThread(Param: Pointer): Integer;
var
Info: TThreadlnfo;
R, C: Integer; // Положение в растре.
Color: TColor; // Цвет пикселя.
Count: Integer; // Количество итераций.
X, Y: Double; // Положение на воображаемой
// плоскости.
Xlncrement, YIncrement: Double; // Шаг изменения координат X и Y.
Scanline: PRgb; // Доступ к изображению выполняется
// построчно.
begin
Result :=0;
Info := TThreadlnfo(Param);
Xlncrement := Info.Bitmap.Width / Zoom;
YIncrement := Info.Bitmap.Height / Zoom;
Y := YOffset;
for R := 0 to Info.Bitmap.Height-1 do
begin
X := XOffset;
Scanline := Info.Bitmap.ScanLine[R];
for C := 0 to Info.Bitmap.Width-1 do
begin
Count := CoroputeIterations(X, Y); // Смотрите процедуру Exit.
X := X + Xlncrement;
// Преобразуем значение максимального числа итераций в цвет
// фона,а другие значения количества итераций - в различные
// цвета путем использования count в качестве значения компо-
// ненты цветового смещения в цветовой схеме.
if Count = Maxlterations then
Color := Background
else
Color := HSV(Count, 255, 255);
Scanline[0] := GetBValue(Color);
Scanline[1] := GetGValue(Color);
Scanline[2] := GetRValue(Color);
Inc(Scanline);
end;
Y := Y + YIncrement;
if Info.Aborted then
begin
PostMessage(Form1.Handle, Wm_Finished, 1, LParam(Param));
Exit;
end;
end;
// Сообщаем основному потоку, что фоновый поток завершил свою
// работу, Передаем объект Threadlrifo в качестве параметра // сообщения.
PostMessage(Form1.Handle, Wm_Finished, 0, LParam(Param));
end;
// Когда фоновый поток завершается, рисуем изображение и освобождаем
// объект Tiireadlnfo.
procedure TForm1.WmFinished(var Msg: TWmFinished);
begin
if not Msg.Info.Aborted then
Image1.Picture.Bitmap := Msg.Info.Bitmap;
FreeAndNil(Msg.Info);
CloseHandle(Thread);
Thread := 0;
end;
// Создаем новый поток для вычисления и формирования множества
// Мандельброта, Info - это запись типа TThreadlnfo, которая
// является закрытым полем класса TForm1. Thread - это THandle,
// тоже закрытое поле.
procedure TForm1.StartThread;
var
Id: Cardinal;
begin
Info := TThreadInfo.Create(lmage1.Width, Image1.Height);
Thread := BeginThread(nil, 0, @HandeAbrotThread, Info, 0, Id);
end;
// Когда форма закрывается, она прерывает поток. Возможно, что сообщение
// Wm_Finished придет после разрушения формы, но это не является
// большой проблемой, т.к. Windows уничтожит поток при завершении
// программы.
procedure TForm1.FormClosed(Sender: TObject);
begin
if Info <> nil then
Info.Abort;
end;
Смотрите также
Нет комментариев.
Оставить комментарий:
|
|