Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi warten bis Thread keine Jobs mehr hat..... (https://www.delphipraxis.net/123299-warten-bis-thread-keine-jobs-mehr-hat.html)

Thomas83 30. Okt 2008 11:29


warten bis Thread keine Jobs mehr hat.....
 
Servus,

habe da einen Thread. In einer Stringliste speicher ich die jobs ab.
Wenn ich meine Anwendung beende, möchte ich noch warten bis alle Jobs verarbeitet wurden.
also bis count = 0 ist. Nur irgend wie funzt dat nicht so kanz... (funzt nur mit application.processmessage)

hier mal ein wenig code
Delphi-Quellcode:
  TSqlThread = class(TThread)
  private
    fSQLTimer : TTimer;
    Procedure OnSqlTimer(Sender : TObject);
  public
    Function IsEmpty : Boolean;
  protected
    Procedure Execute; override;
  end;


function TSqlThread.IsEmpty: Boolean;
begin
  result := fSqlList.Count-1 <= 0;
end;

procedure TSqlThread.OnSqlTimer(Sender: TObject);
begin
  if fSqlList.Count-1 >= 0 then
  begin
    fcs.Enter;
    try
      fDB.SQLQuery(fSqlList[0]);
      fSqlList.Delete(0);
    finally
      fcs.Leave;
    end;
    if Assigned(fOnWriteSQL) then
      Synchronize(fOnWriteSQL);
  end;
end;

procedure TSqlThread.Execute;
var
  MSG : TMsg;
begin
  inherited;

  while (  GetMessage(msg, 0, 0, 0) ) do
    DispatchMessage(msg);
end;

// aus meiner main rufe ich bei einem thread diese methode auf.
begin
  if fsql <> nil then
    while not fsql.IsEmpty do
    begin
      sleep(100);

      //muss ich machen weil sonst OnSqlTimer nicht aufgerufen wird..
      application.ProcessMessages; //was aber nicht sein darf
    end;
end;
Wenn ich es ohne application.ProcessMessages mache friert meine main auch ein.
Bzw. der Timer vom SQLThread wird nicht aufgerufen......

Mache ich was falsch?

guidok 30. Okt 2008 12:11

Re: warten bis Thread keine Jobs mehr hat.....
 
Wieso eigentlich Count-1?

Delphi-Quellcode:
function TSqlThread.IsEmpty: Boolean;
begin
  result := fSqlList.Count = 0;
end;
Sonst würde ja eine Liste, die noch ein Element enthält auch schon als leer interpretiert werden.

sirius 30. Okt 2008 12:26

Re: warten bis Thread keine Jobs mehr hat.....
 
Wo erstellst du denn den Timer?

Thomas83 30. Okt 2008 12:28

Re: warten bis Thread keine Jobs mehr hat.....
 
Zitat:

Zitat von sirius
Wo erstellst du denn den Timer?

im Thread bei Create
Delphi-Quellcode:
constructor TSqlThread.Create(Host,User,Pass,Db : String);
begin
  inherited Create(false);

  fSQLTimer := TTimer.Create(nil);
  fSQLTimer.Interval := 100;    
  fSQLTimer.OnTimer := OnSqlTimer;
  fSQLTimer.Enabled := true;
end;

sirius 30. Okt 2008 12:35

Re: warten bis Thread keine Jobs mehr hat.....
 
Damit ist er im MainThread. Du must ihn in execute erstellen.

btw: Wenn Dein Thread außer dem Timer nichts beinhaltet bzw. den Rest synchronisiert, bringt dir der Timer nichts. du musst alles in den Thread nehmen oder du lässt es mit dem Thread.

Thomas83 30. Okt 2008 12:39

Re: warten bis Thread keine Jobs mehr hat.....
 
aso wuste nicht wenn ich ein object in der create eines Threads anlege das es dann im mainthread ist.....

thx

Thomas83 30. Okt 2008 13:05

Re: warten bis Thread keine Jobs mehr hat.....
 
habe 4 Threadklassen ..... da sehe ich gerade das ich alles in den threads bei create erstelle....
da muss ich das mal ummodeln.....

sirius 30. Okt 2008 13:21

Re: warten bis Thread keine Jobs mehr hat.....
 
Jep, der Constructor ist außerhalb des Threads, der Destructor innerhalb

Thomas83 30. Okt 2008 13:23

Re: warten bis Thread keine Jobs mehr hat.....
 
hmmm das stellt mich jetzt aber vor einem problem.

In der Create des Threads habe ich meine objekte die ich brauche angelegt. (Timer, weiter Thread objekte, server socket etc)
Anschließend wenn ich den Thread in der main erstellt habe, muss ich auf variabeln zugreifen die in der create erstellt wurden..... da jetzt aber alles in der execute erstellt wird, wie soll ich das dann lösen.....

Delphi-Quellcode:
  //alles wird in TThreadServer.Create erstellt
  fServer := TThreadServer.Create('log.text');
  fServer.OnProcCommand := OnGetDataFromAgent;     //<- wie soll ich das dann machen
  fServer.OnClientConnect := OnClientConnect;
  fServer.OnClientDisconnect := OnClientDisconnect;
  fServer.GoOnline(12345);
  fServer.Resume;
einer eine idee

Thomas83 30. Okt 2008 13:41

Re: warten bis Thread keine Jobs mehr hat.....
 
ok habe es jetzt mit einer methode gemacht. Diese wird vom Server aufgerufen wenn alles erstellt wurde.....

hmmm auf einmal läuft alles schneller und ohne fehler.......

vielen dank!!!

sirius 30. Okt 2008 15:16

Re: warten bis Thread keine Jobs mehr hat.....
 
Variablen (also dessen Inhalt) solltest du im Constructor übergeben (Dafür ist er ja da)
Aber so Threadrelevante Dinge, wie Fenster oder Timer erstellen müssen in execute.

Thomas83 30. Okt 2008 15:34

Re: warten bis Thread keine Jobs mehr hat.....
 
jup so habe ich es jetzt auch gemacht.....
jetzt merke ich auch erst das alle Threads gleichzeitig laufen bzw. arbeiten :stupid:

Thomas83 30. Okt 2008 16:05

Re: warten bis Thread keine Jobs mehr hat.....
 
eine frage hätte ich da noch.....

wenn sich ein client beendet wird im thread ondisconnect ausgelöst per syn wird eine methode in der mainform aufgerufen..... wenn ich einen client beende und der inhalt von disconnect wird ausgelöst, friert meine anwendung manchmal ein..... wenn ich den code rausnehme ohne probleme.....

dort werden dann auch daten an einen anderen thread übergeben.... kann es sein das meine threads sich irgend wie stören oder ich zu viele syn methoden eingebaut habe.....

debuggen ist auch nicht gerade einfach.....

Thomas83 31. Okt 2008 05:45

Re: warten bis Thread keine Jobs mehr hat.....
 
vielleicht sind die ganzen TCriticalsection mein Problem....
Maches zur Zeit so ...
Delphi-Quellcode:
TMeinThread1 = class(TThread)
private
  cs : TCriticalsection;
public
  Procedure IrgendEine(str : string);
end;

TMeinThread1.IrgendEine(str : string);
begin
  cs.enter
  try
    flist.add(str); //<- TStringList;
  finally
    cs.leave;
  end;
end;

TMeinThread2 = class(TThread)
private
  meinthread1 : TMeinThread1;
  cs : TCriticalsection;
  fOnProcedure : TProcedure;
public
  Procedure IrgendEine;
  Property OnProcedure : TProcedure read fOnProcedure write fOnProcedure;
  Property MeinThread1 : TMeinThread1 read meinthread1;
end;

TMeinThread2.IrgendEine;
begin
  //mach was
  synchronize(fOnProcedure);
  //mach noch was
end;

//Main
//...
  fMeinThread2.onProcedure := onMeineProcedure;
//...

TFrmMain.OnMeineProcedure;
begin
  fMeinThread2.MeinThread1.add('text');
  //noch irgend was....
end;

Thomas83 31. Okt 2008 06:41

Re: warten bis Thread keine Jobs mehr hat.....
 
habe jetzt noch ein paar test gemacht.....
ich meine ich habe den fehler gefunden.

In einigen Threads deklariere ich die variable für die TCriticalsection unter private der Klasse.
Wenn ich aber in der Methode selber eine cs erstelle und freigebe habe ich keine Probleme, so sieht es nach einem Test zumindestens aus....

sirius 31. Okt 2008 06:45

Re: warten bis Thread keine Jobs mehr hat.....
 
Du darfst nur eine CS für alle Threads haben (bzw. alle die sich zusammen synchronisieren müssen)

Thomas83 31. Okt 2008 06:48

Re: warten bis Thread keine Jobs mehr hat.....
 
:shock: jetzt verstehe ich gar nichts mehr, bzw. habe ich es überhaupt verstanden :)
Das heist ich müste eine globale cs für alle Threads haben....

hmmmm

sirius 31. Okt 2008 06:59

Re: warten bis Thread keine Jobs mehr hat.....
 
Für die Threads, welche du gegenseitig synchronisiewren willst, weil du auf dieselben Variablen zugreifst, ja.

Du kannst natürlich mehrere CS haben. Für jede Variable, die du in mehreren Threads nutzt je eine. Oder eben eine für alle.

Global definieren geht, ist aber nicht ganz OOP. Du kannst sie auch von dem einen Thread zum anderen im Constructor o.ä. übergeben.

alzaimar 31. Okt 2008 07:04

Re: warten bis Thread keine Jobs mehr hat.....
 
Zitat:

Zitat von sirius
Global definieren geht, ist aber nicht ganz OOP. Du kannst sie auch von dem einen Thread zum anderen im Constructor o.ä. übergeben.

Hier wäre eine pragmatische Lösung ('Scheiss auf OOP') allerdings wesentlich einfacher und klarer. :zwinker:

sirius 31. Okt 2008 07:11

Re: warten bis Thread keine Jobs mehr hat.....
 
Zitat:

Zitat von alzaimar
Zitat:

Zitat von sirius
Global definieren geht, ist aber nicht ganz OOP. Du kannst sie auch von dem einen Thread zum anderen im Constructor o.ä. übergeben.

Hier wäre eine pragmatische Lösung ('Scheiss auf OOP') allerdings wesentlich einfacher und klarer. :zwinker:

Ja, schon. Borland hat es ja in seinen Komponenten schön vorgemacht mit den globalen Variablen, gerade bei CS.
Aber was machst du, wenn du mehrere Threads startest (aus verschiedenen Instanzen)?
Ich habe meistens einen kleinen kurzen Thread, den ich starte. Dem übergebe ich sowieso zwei, drei Variablen. Da kann ich ihm auch noch die CS übergeben.

Thomas83 31. Okt 2008 07:17

Re: warten bis Thread keine Jobs mehr hat.....
 
ok gemeinsame variablen habe ich keine.....

habe da eventuell einen deadlock....
Wenn ich Methode1 aus dem Thread auf rufe. Gehe ich in cs.enter. In Methode1 rufe ich Methode2 auf und starte da auch cs.enter. Also wartet Methode2 bis cs.leave aufgerufen wurde. Methode1 wartet bis Methode2 beendet wurde.....

Denke ich mal so, also kann ich es auch nicht mit einer globalen cs machen sondern brauche für jede methode ein cs!?

sirius 31. Okt 2008 08:17

Re: warten bis Thread keine Jobs mehr hat.....
 
gemeinsmae Variablen im weitesten Sinne. Also auch ein Objekt (also ein Zeiger auf denselben Speicherplatz) was in beiden Threads genutzt wird, fällt darunter.


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:36 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz