HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2
НОВЫЕ ТОРГОВАЯ НОВОСТИ ЧАТ
loading...
Скрыть
Вернуться   ANTICHAT > ИНФО > Статьи
   
 
 
Опции темы Поиск в этой теме Опции просмотра

  #1  
Старый 30.03.2012, 16:34
Tip.the.besT
Познающий
Регистрация: 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)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.