
30.03.2012, 16:34
|
|
Познающий
Регистрация: 24.06.2009
Сообщений: 45
С нами:
8884536
Репутация:
0
|
|
Реализация многопоточности в delphi. Вижу множество вопросов на разных форумах по программированию которые относятся к многопоточности. В этой статье я бы хотел не только объяснить как реализовать это в delphi, но и предоставить готовый шаблон многопоточного приложения который вы бы могли использовать в дальнейшем в своих программах.
Для начала немного теории. Одной из важнейших вещей в многопоточном приложении является синхронизация потоков. Если не учесть, синхронизацию потоков, то это, может привести к плачевным последствиям. Давайте рассмотрим такой пример, после чего у вас в голове всё встанет на свои места.
У нас в программе имеется переменная, назовём её - "int" - типа integer. Если мы будем присваивать ей значение из основного потока, то всё будет хорошо, и проблем не возникнет. Мало того, если даже мы присвоим ей значение из дополнительного потока который мы создали, то всё будет хорошо. Но так как зачастую у многопоточного приложения более одного дополнительного потока, то зададимся вопросом- "А, что будет если мы попытаемся присвоить переменной значение из двух потоков одновременно?". Вот тут, и произойдёт то таинственное события при котором переменной присвоится значение которое скорее всего не будет равно ни одному из значений которых вы планировали ей присвоить. Тогда и вступает в игру метод синхронизации synchronize. С помощь данного нам разработчиками delphi метода, вы можете обеспечить безопасное обращение нескольких потоков к одной переменной. Данный метод обеспечивает следующие: при вызове процедуры с помощью synchronize она начинает выполнятся, а все остальные процедуры вызванные с помощью этого метода встают в очередь и ждут выполнения текущей процедуры. Всё вышеописанное относится только к записи переменных, а читать можно одновременно из нескольких потоков и ничего плохого не произойдёт. Ну а теперь перейдём к практике.
И так создадим новый проект. И начнём писать поток. После вот этих строк:
Код:
private
{ Private declarations }
public
{ Public declarations }
end;
Добавим свои:
Код:
potok = class(TThread) //Этой строкой мы унаследовали класс потока
private
str: string;//в разделе private описываются переменные с помощью которых мы
nomer : Integer;//будем передавать значения между процедурами внутри потока
protected
procedure Execute; override;//это главная процедура потока, она начинает свою работу
//после того как мы создали поток
public
procedure synchro;//в разделе public вы можете объявить процедуры какие только душе
//угодно
constructor Create(CreateSuspended: Boolean);//эта строка говорит о том, что мы в
//implementation опишем конструкцию
//потока
end;
Ну здесь вроде бы всё понятно, вы можете добавлять сколько угодно переменных и процедур для удобства работы.
Под implementation нам надо описать конструкцию потока, в данном примере это не обязательно, но, что бы вы знали на будущие мы всё равно это сделаем.
Код:
constructor potok.Create(CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);//Эта строка говорит о том, что поток после создания
//будет приостановлен если ему передать значение true при создание, если false, то сразу
//начнёт работу.
end;
Добавим в глобальные переменные переменную - "nom" - типа integer, а так же массив наших потоков.
Код:
var
Form1: TForm1;
nom:integer;
a: array [1..10] of potok;//массив для хранения наших потоков
Теперь нужно описать процедуры потока, под implementation добавляем следующие:
Код:
procedure potok.Execute;//начинаем описывать главную процедуру потока
var
i:integer;
begin
for i:=0 to 100 do
begin
sleep(1000);
synchronize(synchro);//этой строкой мы вызываем процедуру synchro в единичном экземпляре
end;
end;
procedure potok.synchro; //описываем ещё одну процедуру потока, которая будет менять
//загаловок form1
begin
inc(nom);
form1.Caption:='Поток делает своё дело - '+inttostr(nom);
end;
Собственно всё готово, остаются только запустить потоки. Кидаем кнопку на форму, "кастуем на неё даблклик" и пишем:
Код:
procedure TForm1.Button1Click(Sender: TObject);
var
pot:integer;
begin
for pot:=1 to 10 do //цикл запускает 10 потоков, которые будут изменять заголовок
a[pot]:=potok.Create(false); //формы, так же идёт
//добавление в массив, что бы потом вы могли уничтожить
//один поток.
end;
Вот так выглядит программа в итоге:
Код:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
potok = class(TThread) //Этой строкой мы унаследовали класс потока
private
str: string;//в разделе private описываются переменные с помощью которых мы
nomer : Integer;//будем передавать значения между процедурами внутри потока
protected
procedure Execute; override;//это главная процедура потока, она начинает свою работу
//после того как мы создали поток
public
procedure synchro;//в разделе public вы можете объявить процедуры какие только душе
//угодно
constructor Create(CreateSuspended: Boolean);//эта строка говорит о том, что мы в
//implementation опишем конструкцию
//потока
end;
var
a: array [1..10] of potok;
Form1: TForm1;
nom:integer;
implementation
constructor potok.Create(CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);//Эта строка говорит о том, что поток после создания
//будет приостановлен если ему передать значение true при создание, если false, то сразу
//начнёт работу.
end;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
pot:integer;
begin
for pot:=1 to 10 do //цикл запускает 10 потоков, которые будут изменять заголовок
a[pot]:=potok.Create(false); //формы, так же идёт добавление в массив, что бы потом вы могли их уничтожить по одному.
end;
procedure potok.Execute;//начинаем описывать главную процедуру потока
var
I:integer;
begin
for i:=0 to 100 do
begin
sleep(1000);
synchronize(synchro);//этой строкой мы вызываем процедуру synchro в единичном экземпляре
end;
end;
procedure potok.synchro; //описываем ещё одну процедуру потока, которая будет менять
//загаловок form1
begin
inc(nom);
form1.Caption:='Поток делает своё дело - '+inttostr(nom);
end;
end.
Запускаем программу, и нажимаем на кнопку. И видим как в заголовке формы по очереди увеличивается число. ЧТД как говорится. Удачи в создание приложений.
С уважением Tip.the.besT.
Автор: Tip.the.besT
|
|
|
|
|
Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
|
|
|
|