Avatar billede kloge Nybegynder
11. maj 2012 - 17:28 Der er 1 kommentar og
2 løsninger

Asynkron kørsel af Tnotifyevent

Jeg er generelt ikke stor tilhænger af tråde, men er røget ud i en situation, hvor jeg har nogle opgaver i mit program, som egner sig til at køre i baggrunden. Jeg vil gerne kunne kalde disse opgaver med en simpel TnotifyEvent ala:

procedure TForm1.DoSomething(Sender : Tobject);
begin
  //
end;

det ville være perfekt, hvis denne kunne kaldes som:

dmAsync.Execute(DoSomething, Sender);

Som starter et baggrundsjob og returnerer umiddelbart efter.

Fejlbehandling skal klares efterfølgende.

Til formålet har jeg lavet denne kode, som  desværre giver en fejlmeddelelse:

Threaderror: Handlen er ikke gyldig(6)

når modulet skabes og Execute(SampleMethod, nil) kaldes.

Er der nogen der har et bud på hvordan det skal laves?

unit udmAsyncCall;

interface

uses
  SysUtils, Classes, ExtCtrls;

type
  TdmAsync = class(TDataModule)
    Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
    procedure DataModuleCreate(Sender: TObject);
    procedure Execute(Method : tNotifyEvent; Sender : tObject);
    procedure SampleMethod(sender : tobject);
  private
    { Private declarations }

    ThreadList : tlist;
  public
    { Public declarations }
  end;

var
  dmAsync: TdmAsync;

implementation

{$R *.dfm}



type

tMythread = class (TThread)
constructor Create(aMethod : Tnotifyevent; aSender : tobject);
private
  method : tNotifyevent;
  sender : tobject;
protected
procedure Execute; override;
end;




{ tMythread }

constructor tMythread.Create(amethod: Tnotifyevent; aSender: tobject);
begin
priority :=  tpLower;
  method := amethod;
  sender := aSender;
end;

procedure tMythread.Execute;
begin
  inherited;

  method(sender);

end;

procedure TdmAsync.Execute(method: tNotifyEvent; sender: tObject);
begin
  tmythread.create(method, sender);
end;

procedure TdmAsync.DataModuleCreate(Sender: TObject);
begin
  threadlist := tlist.create;
  execute(samplemethod, nil);
end;

procedure TdmAsync.Timer1Timer(Sender: TObject);
var i : integer;
    t : tMythread;
begin
  // Fejlbehandling, skal udbygges...
  for i := 0 to threadlist.count-1 do
  if tmythread(threadlist[i]).Terminated then
  begin
    t := threadlist[i];
    threadlist.Delete(i);
    t.Free;
    exit;
  end;

end;

procedure TdmAsync.SampleMethod(sender: tobject);
begin
  sleep(1000);
end;

end.
Avatar billede kloge Nybegynder
15. maj 2012 - 09:45 #1
Beginthread funker:


type tparam = record
  event : tnotifyevent;
  sender : tobject;
end;

type
pparam = ^tparam;


function ThreadFunc( p : pparam ) : integer;
begin
  with p ^do
  try
    event(sender);
    result := 0;
  except
    result := 1;
  end;
end;

procedure AsyncExec(event : tnotifyevent; sender : tobject);
var p : pparam;
    ThreadId : longword;
begin
  new(p);
  p^.event := event;
  p^.sender := sender;
  beginthread(nil, 0, @ThreadFunc, pointer(p), 0, ThreadId);
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  AsyncExec(Button2click, button2);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
sleep(30000);
sender := sender;
end;
Avatar billede kloge Nybegynder
15. maj 2012 - 10:27 #2
Og her med fejlhåndtering:


var ThreadList : tlist;

type tparam = record
  event : tnotifyevent;
  sender : tobject;
  status : integer;
  errormessage, jobname : string;
end;

type
pparam = ^tparam;


function ThreadFunc( p : pparam ) : integer;
begin
  with p ^do
  try
    status := 0;
    event(sender);
    status := 1;
  except
    on e : exception do
    begin
      status := -1;
      errormessage := e.Message;
    end;
  end;
  endthread(0);
end;

procedure AsyncExec(event : tnotifyevent; sender : tobject; Jobname : string = 'Asyncjob');
var p : pparam;
    ThreadId : longword;
begin
  new(p);
  p^.event := event;
  p^.sender := sender;
  p^.jobname := Jobname;
  ThreadList.add(p);
  beginthread(nil, 0, @ThreadFunc, pointer(p), 0, ThreadId);

end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  AsyncExec(Button2click, button2, 'Button2 job');
end;

procedure TForm1.Button2Click(Sender: TObject);
var t : integer;
begin
sleep(1000);
t:= 0;
t := round(1/t);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  threadlist := tlist.create;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var i : integer;
begin
  for i := 0 to ThreadList.count-1 do
  with pparam(ThreadList[i])^ do
  if status <> 0 then
  begin
  threadlist.delete(i);
  if status = -1 then
  begin
    raise exception.Create(
    'Job named '+jobname+' returned error: '+
    errormessage)
  end;
  end;
end;
Avatar billede kloge Nybegynder
23. oktober 2012 - 16:24 #3
Spørgsmål lukket
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester