Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Multithreading??


neuling82 - Do 31.07.03 10:22
Titel: Multithreading??
Hey Leute, ich habe folgendes Problem. Aus einer DLL datei habe ich einer Funktion, die mir einer E-Mail verschickt. Während dies passiert, ist meine Anwendung aber praktisch "stillgelegt"ich kann keinen Button mehr drücken, nicht mal mehr den aktuellen status des Sendevorgangs darstellen. Wie kann ich dieses "lahmlegen" denn verhindern??


Tana´Ri - Do 31.07.03 10:26

du must diesen bearbeitungsvorgang in einen TThread auslagern


neuling82 - Do 31.07.03 10:30

kannst du mir mal einen Tip geben, wie ich das mache? Ich habe zwar schon mal im Tutorial gelesen ober da seheh ich nur schwar...kleien Hilfe evtl?!


Tana´Ri - Do 31.07.03 11:04

es gibt viele wege, einer wäre wenn du ne mail schicken willst dir einen thread zu erzeugen, der per constructor die notwendigen infos mitbekommt und dann die Nachricht verschickt (der thread greift die dll funktion auf).

könnte so aussehn bsp:
(hab sowas noch net gemacht mit EMail und kenn deine Dll Fkt auch net!)

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
uses
  Classes;

type
  Thr_eMailer = class(TThread)
  private
   fmailaddr,fmailtext : string;
    { Private-Deklarationen }
  protected
    procedure Execute; override;
  public
   constuctor Create(CreateSuspended: Boolean; MailAddr, MailText : string);
  end;

implementation

{ Thr_eMailer }

procedure Thr_eMailer.Execute;
begin
  { Thread-Code hier einfügen }
  YourDLLFunction_PostEMail(EMailAddr,EMailtext); // mail verschicken
  suspend; // schlafen schicken nach getaner arbeit
end;

{ im form btnmailsendclick zb }
begin
 with myThread.Create(false,...) do
 try
  repeat
  until (suspended); // solange er nicht schläft 
 finally
  terminate;
  waitfor;
  free;
 end
   
end;
end.


Moderiert von user profile iconTino: Delphi-Tags hinzugefügt.


neuling82 - Do 31.07.03 11:30

danke für diesen Tip, das scheint mir echt logisch nur habe ich damit noch ein Problem...Ich schreibe eine Komponente. darin gibt es nun zwei objekte: Den Thread und eine zum senden. Das object zum senden hat eigenschaften, die man im Objektinspektor später einstellen kann(Adresse, text...) diese kann ich aber nun nicht im Threadobjekt zuweisen, da ich von diesem nicht auf das Sendeobjekt zugreifen kann, denn es ist nicht erzeugt.


Tana´Ri - Do 31.07.03 11:40

erzeugst du dieses sendeobjekt erst wenn du ne mail sendest ?

du könntest dem Thread im Constructor eine Referenz dieses objektes übergeben und somit über diese referenz darauf zugreifen.
Ich versteh anscheinend die problematik nicht 100%ig?


neuling82 - Do 31.07.03 11:54

doch die Antwort war schon richtig, du hast mich schon verstanden, so werde ich es auch machen, vielen dank! Ich hoffe es klappt ;-))


neuling82 - Do 31.07.03 12:09

und wo wird hier eigendlich myThread.execute aufgerufen?


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
{ im form btnmailsendclick zb } 
begin 
with myThread.Create(false,...) do 
try 
  repeat 
  until (suspended); // solange er nicht schläft 
finally 
  terminate; 
  waitfor; 
  free; 
end
    
end;

was bedeuter waitfor, terminate?


neuling82 - Do 31.07.03 12:27

ich bekomme jedesmal den Fehler ungültiges Handle...was mache ich denn falsch??


Tana´Ri - Do 31.07.03 12:33

als erstes bin selbst relativ neu, pogrammiere seit knapp einem jahr, aber ich wills versuchen :shock:


terminate ist eine procedure des TThread, das die terminierung (Free) auslöst, mit waitfor warten wir bis der thread aus seinem Ausführbereich (Execute) heraustritt und somit bereit ist zur freigabe. meist wird im execute eine repeat until terminated Schleife verwendet, was bedeutet tue [...] solange nicht terminate kommt.

Execute brauchst du nicht und kannst du nicht aufrufen dass ist eine protected virtual procedure.
Aus der hilfe
Zitat:

Die Methode Execute stellt eine abstrakte Methode bereit, die den auszuführenden Code enthält.

procedure Execute; virtual; abstract;

Beschreibung

Überschreiben Sie diese Methode, und fügen Sie den Code des Threads ein, der ausgeführt werden soll. Execute übernimmt die Prüfung von Terminated und stellt dadurch fest, ob der Thread beendet werden muß.

Ein Thread wird ausgeführt, wenn Create aufgerufen wird, während CreateSuspended den Wert False hat, oder wenn Resume zuerst nach dem Erzeugen des Threads aufgerufen wird, wobei CreateSuspended auf True steht.

Hinweis

Verwenden Sie die Eigenschaften und Methoden anderer Objekt nicht direkt in der Methode Execute eines Threads. Setzen Sie dazu einen separaten Prozedurenaufruf ein und rufen Sie diese Prozedur auf, indem Sie sie als Parameter an die Methode Synchronize übergeben.


Tana´Ri - Do 31.07.03 12:35

handle? was? wo?


derDoc - Do 31.07.03 13:13

MyThread.Execute wird automatisch in deinem Programm aufgerufen, wenn du
a) In MyThread.Create Suspended auf False setzt oder
b) im Programm MyThread.Resume; aufrufst


neuling82 - Do 31.07.03 13:21

ja, ich bekomme, wenn ich den Code so schreibe wie du ihn gepostet hast immer die Meldung handle ungültig


neuling82 - Do 31.07.03 16:06

ich habe das ganze nun wie folgt gelöst:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
var
  sende_thread: cardinal;
  Form1: TForm1;
  i: integer = 0;
 function senden_fx(p: pointer): integer;
implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
ThreadID: LongWord;
begin
sende_thread:= beginthread(nil,0,@senden_fx, nil0, ThreadID);

//smstool1.senden('test');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
//memo1.Lines:=smstool1.sendeprotokoll;
end;

function senden_fx(p: pointer): integer;
begin
form1.SMStool1.senden('text');
end;


form1.smstool1.senden('text '). wird ausgeführt. diese Funktion hatte zuvor immer meine Anwendung blockiert. Jetzt tut sie es nicht mehr, jedoch scheint es mir als werde die Funktion nicht bis zum ende ausgeführt, woran kann das liegen??


neuling82 - Sa 02.08.03 12:44

kann mir jemand noch mal das Prinzip eines Threads etwas genauer erklären? Also ich rufe den Constructor auf mit false ls erstem Parameter, damit wir doch der Thread erzeugt´, aber noch nicht ausgeführt oder? In execute schreibe ich meinen Code rein (eine Funktion mit einer Schleife di angenommen 10 sek. dauert). Wenn ich den Thread starte wir der Code in Execute ausgeführt. wie starte ich den Thread?

Zitat:
"mit waitfor warten wir bis der thread aus seinem Ausführbereich (Execute) heraustritt und somit bereit ist zur freigabe"

wie veranlass ich den Thread aus seinem ausführbaren bereich auszutreten, macht er dass, wenn meine 10sek. schleife fertig ist und danach nichts mehr folgt automatisch? wird der Code in Execute dauernd ausgeführt oder nur einmal und das wars? Denn wenn der Thread nach dem Ende des Execute Codes fertig ist, durfte er nicht mehr weiterlaufen, sonst würde sich der Programmcode ewig wiederholen, bis ich (von außen?) sage dass er aufhören soll??

Sorry für die (evtl dummen) Fragen aber ich bin noch neu auf diesem Gebiet und möchte schnell dazu lernen.

Danke


neuling82 - Mo 04.08.03 22:29

angenommen die Procedure Execute in meinem Thread enthält eine Procedure, welche 10 Sekunden dauert, bis sie zu ende ist, dauert dann auch der Thread ca 10 sekunden oder ist er nach dem Aufruf der Procedure fertig und diese wird trotzdem weiter ausgeführt? wenn ich den Thread anhalt und die funktion oder Procedure in execute aus einer DLL kommt, wird dann auch der code in der dll angehalten, stoppt die externe Procedure dann auch? ich verstehe das Prinzip glaube ich noch nicht so ganz, daher nochmals bitte um hilfe!