Блог по программированию в среде Delphi

Поиск по блогу

Есть идея по созданию интересной программы?

Опиши тут и я по возможности постараюсь это реализовать специально для тебя! Без $ ))

суббота, 16 октября 2010 г.

Многопотоковая обработка.

Задание 1 на текущую сессию))

Пример: выполнить имитатор гонок (в просторечии эта задача известна как «тараканьи бега» ) при помощи создания нескольких потоков. Каждый поток обслуживает свою «беговую дорожку». На исполнение все потоки запускаются одновременно, после  чего потоки произвольным образом приостанавливаются и запускаются вновь функциями SuspendThread() и ResumeThread().

На исполнение каждому потоку выделяется квант времени (например, 500 мс или 1 с). За этот период поток производит выполнение задачи, например, увеличивает позицию гонщика на некоторую величину. После истечения кванта времени поток приостанавливается на производный период времени, определяемый при помощи генератора случайных чисел.
После завершения гонки производиться выдача результатов(очередность завершения).
Завершение потока после завершения исполнения можно произвести при помощи функций ExitThread() и TerminateThread().



Использование класса TThread, включенного в поставку interise Delphi или C++ Builder, допускается в ознакомительных целях.


Сделал вот так, на счет 100% правильности конечно говорить не приходиться, но думаю, что правильно. Кто ни чего не делает то не ошибается))

unit unitMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls;

const
  PROGRESS_POS = WM_USER+1;//установка значения
  EXITTHREAD_MESSAGE=WM_USER+2;//выход из потока
type
  TfrmMain = class(TForm)
    ProgressBar1: TProgressBar;
    ProgressBar2: TProgressBar;
    ProgressBar3: TProgressBar;
    ProgressBar4: TProgressBar;
    ProgressBar5: TProgressBar;
    btnStart: TButton;
    btnStop: TButton;
    btnClear: TButton;
    btnExit: TButton;
    Memo1: TMemo;
    Label1: TLabel;
    procedure btnStartClick(Sender: TObject);
    procedure btnStopClick(Sender: TObject);
    procedure btnClearClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure btnExitClick(Sender: TObject);
  private
    { Private declarations }
    procedure SetProgressPos(var Msg: TMessage); message PROGRESS_POS;
    procedure MSExitThread(var Msg: TMessage); message EXITTHREAD_MESSAGE;
  public
    { Public declarations }
  end;

  //процедура выполняемая в отдельном потоке
  procedure procedurePotoc1(aValue:PInteger);stdcall;
const
  countThread=5;//кол-во потоков

var
  frmMain: TfrmMain;
  thread:array[1..countThread] of THandle;//массив для хранения
  threadID:array[1..countThread] of DWORD;
  bStop,vse:Boolean;
  Poriadok:TStringList;
implementation

{$R *.dfm}
//процедура выполняемая в отдельном потоке
procedure procedurePotoc1(aValue:PInteger);stdcall;
var
  i:Integer;
begin
  for I := 0 to 100 do
  begin
    Randomize;
    Sleep(Random(100)+50);
    SendMessage(frmMain.Handle,PROGRESS_POS, aValue^, i);
  end;
  SendMessage(frmMain.Handle,EXITTHREAD_MESSAGE, aValue^, 0);
end;

procedure TfrmMain.btnClearClick(Sender: TObject);
var
  i:Integer;
begin
  for i := 1 to countThread do
  begin
    if thread[i]>0 then //проверка того, что он вообще запускался))
      if TerminateThread(thread[i],0) then
        thread[i]:=0;
  end;
  ProgressBar1.Position:=0;
  ProgressBar2.Position:=0;
  ProgressBar3.Position:=0;
  ProgressBar4.Position:=0;
  ProgressBar5.Position:=0;
  Poriadok.Clear;
  Memo1.Lines.Clear;
end;

procedure TfrmMain.btnExitClick(Sender: TObject);
begin
  frmMain.Close;
end;

procedure TfrmMain.btnStartClick(Sender: TObject);
var
  i:Integer;
  n:Integer;
begin
  for i := 1 to countThread do
  begin
    if thread[i]=0 then
    begin
      thread[i]:=CreateThread(nil,0, @procedurePotoc1, @thread[i], 0, threadID[i]);
    end;
    if (thread[i] = 0) then
      ShowMessage('Поток не создан '+IntToStr(i));
  end;
  Poriadok.Clear;
end;

procedure TfrmMain.btnStopClick(Sender: TObject);
var
  i:Integer;
begin
  for i := 1 to countThread do
  begin
    if bStop then
    begin
      ResumeThread(thread[i]);
    end
    else
    begin
      SuspendThread(thread[i]);
    end;
  end;
  if bStop then
    bStop:=False
  else
    bStop:=True;
end;

procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  btnClearClick(Self);
  Poriadok.Free;
end;


procedure TfrmMain.FormCreate(Sender: TObject);
begin
  Poriadok:=TStringList.Create;
end;

procedure TfrmMain.MSExitThread(var Msg: TMessage);
var
  i:Integer;
  temp:cardinal;
begin
  temp:=0;
  for I := 1 to countThread do
  begin
    if thread[i]=Msg.WParam then
    begin
      thread[i]:=0;
      Poriadok.Add('"Таракан" №'+IntToStr(i));
    end;
    temp:=temp+thread[i];
    if temp=0 then//все потоки завершились или нет
      vse:=True
    else
      vse:=False;
  end;
  if vse then//все потоки завершились или нет
    Memo1.Lines:=Poriadok;
end;

procedure TfrmMain.SetProgressPos(var Msg: TMessage);
var
  i:Integer;
  n:Integer;
  hN:THandle;
begin
  for i:= 1 to countThread  do
  begin
    if thread[i]=Msg.WParam then
      TProgressBar(Self.FindComponent('ProgressBar'+IntToStr(i))).Position:=Msg.LParam;
  end;
end;
end.

Синхронизацию с VCL реализовал путем обмена сообщениями.

Скачать исходник можно отсюда Download

Комментариев нет:

Отправить комментарий