|
Тема |
Re: actions, threads, chain-of-actions [re: tikva] |
|
Автор | tikva (Нерегистриран) | |
Публикувано | 22.06.07 14:49 |
|
|
някой има ли желание да погледне и да ми направи едно кратко code review :)
видимо работи, обаче незнам дали съм сложил данните, които се ползват от main и от runner thread-а на правилното място (в случая - глобални:) и т.н.
unit ActionRunner;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, SyncObjs, ActnList;
type
TClientActionCallback = procedure (const result: boolean) of object;
{ TClientAction }
TClientAction = class
action: TAction;
callback: TClientActionCallback;
constructor Create(const a: TAction; const cbk: TClientActionCallback);
end;
TClientActionChain = array of TClientAction;
{ TClientActionRunnerThread }
TClientActionRunnerThread = class(TThread)
procedure Execute; override;
private
finished: boolean;
function GetNextInChain(): TClientAction;
end;
{ TClientActionRunner }
TClientActionRunner = class
public
constructor Create;
destructor Destroy; override;
procedure InitChain(const ch: TClientActionChain);
procedure StartChain;
procedure SetUserAction(const ua: TClientAction);
Done: procedure(Sender: TObject) of object;
private
runnerThread: TClientActionRunnerThread;
end;
var
actrunLock: TCriticalSection;
chain: TClientActionChain;
chainIndex: integer;
userAction: TClientAction;
implementation
{ TClientActionRunner }
constructor TClientActionRunner.Create;
begin
actrunLock := TCriticalSection.Create;
end;
destructor TClientActionRunner.Destroy;
begin
FreeAndNil(actrunLock);
inherited Destroy;
end;
procedure TClientActionRunner.InitChain(const ch: TClientActionChain);
begin
chain := ch;
end;
procedure TClientActionRunner.StartChain;
begin
chainIndex := -1;
runnerThread := TClientActionRunnerThread.Create(true);
runnerThread.FreeOnTerminate := true;
runnerThread.OnTerminate := Done;
runnerThread.Resume;
end;
procedure TClientActionRunner.SetUserAction(const ua: TClientAction);
begin
actrunLock.Enter;
try
userAction := ua;
chainIndex := -1;
finally
actrunLock.Leave;
end;
end;
{ TClientActionRunnerThread }
function TClientActionRunnerThread.GetNextInChain(): TClientAction;
begin
result := nil;
actrunLock.Enter;
try
if (chainIndex = -1) then
begin
if (userAction <> nil) then
begin
result := userAction;
userAction := nil;
exit;
end
end;
Inc(chainIndex);
if (chainIndex < Length(chain)) then
result := chain[chainIndex];
finally
actrunLock.Leave;
end;
end;
procedure TClientActionRunnerThread.Execute;
var
ca: TClientAction;
ok: boolean;
begin
while (not terminated) do
begin
ca := GetNextInChain();
if (ca = nil) then // no next action - i.e. chain finished
break;
ok := ca.action.Execute();
ca.callback(ok);
end;
end;
{ TClientAction }
constructor TClientAction.Create(const a: TAction;
const cbk: TClientActionCallback);
begin
action := a;
callback := cbk;
end;
end.
a това е тестовата формичка, от която се ползва:
unit chainMain;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, ActnList,
StdCtrls, ExtCtrls, Buttons;
type
{ TForm1 }
TForm1 = class(TForm)
aFinishRefreshing: TAction;
aRefreshStep5: TAction;
aRefreshStep4: TAction;
aRefreshStep3: TAction;
aRefreshStep2: TAction;
aUserAction2: TAction;
aRefreshStep1: TAction;
aUserAction1: TAction;
ActionList1: TActionList;
btnUserAction1: TButton;
btnUserAction2: TButton;
Memo1: TMemo;
Timer1: TTimer;
procedure aFinishRefreshingExecute(Sender: TObject);
procedure aRefreshStep1Execute(Sender: TObject);
procedure aRefreshStep2Execute(Sender: TObject);
procedure aRefreshStep3Execute(Sender: TObject);
procedure aRefreshStep4Execute(Sender: TObject);
procedure aRefreshStep5Execute(Sender: TObject);
procedure aUserAction1Execute(Sender: TObject);
procedure aUserAction2Execute(Sender: TObject);
procedure btnUserAction1Click(Sender: TObject);
procedure btnUserAction2Click(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ private declarations }
procedure RefreshStep1Done(const result: boolean);
procedure RefreshStep2Done(const result: boolean);
procedure RefreshStep3Done(const result: boolean);
procedure RefreshStep4Done(const result: boolean);
procedure RefreshStep5Done(const result: boolean);
procedure RefreshingDone(Sender: TObject);
procedure UserAction1Done(const result: boolean);
procedure UserAction2Done(const result: boolean);
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{ TForm1 }
uses
ActionRunner;
var
runner: TClientActionRunner;
procedure TForm1.FormShow(Sender: TObject);
var
chain: TClientActionChain;
ca: TClientAction;
begin
SetLength(chain, 5);
ca := TClientAction.Create(aRefreshStep1, @RefreshStep1Done);
chain[0] := ca;
ca := TClientAction.Create(aRefreshStep2, @RefreshStep2Done);
chain[1] := ca;
ca := TClientAction.Create(aRefreshStep3, @RefreshStep3Done);
chain[2] := ca;
ca := TClientAction.Create(aRefreshStep4, @RefreshStep4Done);
chain[3] := ca;
ca := TClientAction.Create(aRefreshStep5, @RefreshStep5Done);
chain[4] := ca;
{
ca := TClientAction.Create(aFinishRefreshing, @FinishRefreshingDone);
chain[5] := ca;
}
runner := TClientActionRunner.Create;
runner.Done := @RefreshingDone;
runner.InitChain(chain);
end;
procedure TForm1.aRefreshStep1Execute(Sender: TObject);
begin
Memo1.Lines.Add('refreshstep1 start');
sleep(1000);
end;
procedure TForm1.aFinishRefreshingExecute(Sender: TObject);
begin
Memo1.Lines.Add('refreshing finished');
end;
procedure TForm1.aRefreshStep2Execute(Sender: TObject);
begin
Memo1.Lines.Add('refreshstep2 start');
sleep(2000);
end;
procedure TForm1.aRefreshStep3Execute(Sender: TObject);
begin
Memo1.Lines.Add('refreshstep3 start');
sleep(3000);
end;
procedure TForm1.aRefreshStep4Execute(Sender: TObject);
begin
Memo1.Lines.Add('refreshstep4 start');
sleep(4000);
end;
procedure TForm1.aRefreshStep5Execute(Sender: TObject);
begin
Memo1.Lines.Add('refreshstep5 start');
sleep(1000);
end;
procedure TForm1.aUserAction1Execute(Sender: TObject);
begin
Memo1.Lines.Add('user action 1 start');
sleep(2000);
end;
procedure TForm1.aUserAction2Execute(Sender: TObject);
begin
Memo1.Lines.Add('user action 2 start');
sleep(2000);
end;
procedure TForm1.btnUserAction1Click(Sender: TObject);
var
ca: TClientAction;
begin
ca := TClientAction.Create(aUserAction1, @UserAction1Done);
runner.SetUserAction(ca);
end;
procedure TForm1.btnUserAction2Click(Sender: TObject);
var
ca: TClientAction;
begin
ca := TClientAction.Create(aUserAction2, @UserAction2Done);
runner.SetUserAction(ca);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := false;
runner.StartChain;
end;
procedure TForm1.RefreshStep1Done(const result: boolean);
begin
Memo1.Lines.Add('refreshstep1 done');
end;
procedure TForm1.RefreshStep2Done(const result: boolean);
begin
Memo1.Lines.Add('refreshstep2 done');
end;
procedure TForm1.RefreshStep3Done(const result: boolean);
begin
Memo1.Lines.Add('refreshstep3 done');
end;
procedure TForm1.RefreshStep4Done(const result: boolean);
begin
Memo1.Lines.Add('refreshstep4 done');
end;
procedure TForm1.RefreshStep5Done(const result: boolean);
begin
Memo1.Lines.Add('refreshstep5 done');
end;
procedure TForm1.RefreshingDone(Sender: TObject);
var
en: boolean;
begin
Timer1.Enabled := true;
en := Timer1.Enabled;
end;
procedure TForm1.UserAction1Done(const result: boolean);
begin
Memo1.Lines.Add('user action 1 done');
end;
procedure TForm1.UserAction2Done(const result: boolean);
begin
Memo1.Lines.Add('user action 2 done');
end;
initialization
{$I chainMain.lrs}
end.
|
| |
|
|
|