Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi TThread - Sleep (https://www.delphipraxis.net/152808-tthread-sleep.html)

JoltinJoe 7. Jul 2010 18:50

TThread - Sleep
 
Ich hab nochmal eine Frage zu TThread:

Und zwar muss einen Thread in den Schlaf versetzen. Wenn ich Sleep() im Thread aufrufe schläft allerdings das ganze Programm ein...Ich möchte aber nur diesen einen Thread einschläfern. Hat jemand eine Idee ?

sirius 7. Jul 2010 18:53

AW: TThread - Sleep
 
Dann ist etwas mit dem Thread falsch.

mkinzler 7. Jul 2010 18:54

AW: TThread - Sleep
 
Zum Beispiel mit TTHread.SpinWait()

himitsu 7. Jul 2010 18:54

AW: TThread - Sleep
 
Sleep legt nur den einen Thread einschlafen, in Welchem es aufgerufen wird.

Wenn das gesamte Programm hängt, dann machst du was falsch.
- z.B. sleep in Synchronize aufrufen
- oder der Hauptthread "wartet" auf etwas, vom Thread, bzw. welches vom Thread noch gesperrt ist

JoltinJoe 7. Jul 2010 19:16

AW: TThread - Sleep
 
Zitat:

Zitat von himitsu (Beitrag 1034116)
Sleep legt nur den einen Thread einschlafen, in Welchem es aufgerufen wird.

Wenn das gesamte Programm hängt, dann machst du was falsch.
- z.B. sleep in Synchronize aufrufen
- oder der Hauptthread "wartet" auf etwas, vom Thread, bzw. welches vom Thread noch gesperrt ist

Okay deine erste Vermutung war auch meine erste, die kann ich ausschließen. Deine zweite Vermutung kann ich eigentlich auch ausschließen...Ich werde nochmal ein bisschen was testen und mich wieder melden ;)

ChrisE 8. Jul 2010 07:14

AW: TThread - Sleep
 
Hallo,

aber der Thread legt sich schon selber schlafen?

Also innerhalb seiner Execute-Methode merkt er irgendwann selber, dass er sich schlafen legen kann und ruft selber Sleep auf.
Delphi-Quellcode:
procedure TMeinThread.Exececute;
begin
  while not Terminated do
  begin
    // mach ganz viel
 
    if SchlafbedingungErfuellt then
      Sleep(1000);
  end;
//....
end;
Greez, Chris

xZise 8. Jul 2010 07:19

AW: TThread - Sleep
 
Moin,
wie startest du den Thread?

MfG
Fabian

JoltinJoe 8. Jul 2010 09:07

AW: TThread - Sleep
 
Zitat:

Zitat von ChrisE (Beitrag 1034154)
Hallo,

aber der Thread legt sich schon selber schlafen?

Also innerhalb seiner Execute-Methode merkt er irgendwann selber, dass er sich schlafen legen kann und ruft selber Sleep auf.
Delphi-Quellcode:
procedure TMeinThread.Exececute;
begin
  while not Terminated do
  begin
    // mach ganz viel
 
    if SchlafbedingungErfuellt then
      Sleep(1000);
  end;
//....
end;
Greez, Chris

Ja, genauso habe ich es !

Zitat:

Zitat von xZise (Beitrag 1034155)
Moin,
wie startest du den Thread?

MfG
Fabian

Habe jetzt keinen SourceCode zur Hand aber ich glaube es war "MyThread.Resume" .. werde heute Nachmittag das Problem nochmal genauer analysieren und ggf. eine neue Beschreibung posten :)

bYe

JoltinJoe 8. Jul 2010 16:47

AW: TThread - Sleep
 
Delphi-Quellcode:
//High Condition
procedure TSendThread.HighCondition;
begin
  FetchedCount:=FetchedCount+1;
end;

//Reset Condition
procedure TSendThread.ResetCondition;
begin
  FetchedCount:=0;
end;

procedure TSendThread.Execute;
begin
  while not Terminated do
  begin
    Synchronize(HighCondition);
    if FetchedCount>ConditionLimit then
      begin
        Sleep(Delay);
        Synchronize(ResetCondition);
      end;
      ....
      MEINE_ANDEREN_PROCEDUREN
      ....
  end;
end;
FetchedCount und ConditionLimit sind globale Variablen. FetchedCount wird nur im Synchronize beschrieben, ConditionLimit wird nur gelesen!

Grundlage: Ich habe immer 100 Threads. Wenn ich das Limit auf 50 setze dann sollen 50 Threads MEINE_ANDEREN_PROCEDUREN ausführen und 50 sollen erstmal schlafen und dann MEINE_ANDEREN_PROCEDUREN ausführen !

xZise 8. Jul 2010 17:04

AW: TThread - Sleep
 
Wann wird denn CheckCondition aufgerufen? Eventuell ist dort synchronisiert.

Und was macht der Mainthread, nachdem du es laufen lässt?

MfG
Fabian

JoltinJoe 8. Jul 2010 17:20

AW: TThread - Sleep
 
Das hat sich ein Fehler beim kopieren eingeschlichen... "CheckCondition" kann außer Acht gelassen werden, habe es auch im Vor-Thread entfernt...

Nach dem Start der Threads schläft das ganze Programm sofort und danach führen alle Threads "MEINE_ANDEREN_PROCEDUREN" aus.



Edit:

Wenn ich die 100 Aufgaben anstatt auf 100 Threads nur auf 1 Thread lege dann klappt es. 50 werden ausgeführt, dann wird geschlafen und dann kommen die anderen 50.

Wenn ich die 100 Aufgaben auf 100 Threads lege dann wird erst geschlafen und dann werden alle 100 Threads mit einem mal abgearbeitet.

JoltinJoe 8. Jul 2010 19:00

AW: TThread - Sleep
 
Delphi-Quellcode:
procedure TMyOwnThread.HighCondition;
begin
  FetchedCount:=FetchedCount+1;
end;

procedure TMyOwnThread.ResetCondition;
begin
  FetchedCount:=0;
end;

procedure TMyOwnThread.WriteResults;
begin
  Form1.Memo1.Lines.Add('blaa');
end;

procedure TMyOwnThread.Execute;
begin
  while not Terminated do
  begin
    Synchronize(HighCondition);
    if FetchedCount>50 then
    begin
      Sleep(10000);
      Synchronize(ResetCondition);
    end;
    Synchronize(WriteResults);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Thread: TMyOwnThread;
  ThreadCount: Integer;
begin
  ThreadCount:=100;
  for i:=0 to ThreadCount-1 do
    begin
      Thread:=TMyOwnThread.Create(True);
      Thread.FreeOnTerminate := True;
      Thread.Resume;
    end;
end;

Habe hier nochmal den kompletten Code zur Veranschaulichung gekürzt ..

xZise 8. Jul 2010 20:36

AW: TThread - Sleep
 
Moin,
Und so funktioniert er nicht? Weil ich kann da keine Probleme erkennen. Wobei natürlich 100 Threads via Sync schon heftig ist.

Wäre da nicht eventuell eine Delphi-Referenz durchsuchenTCriticalSection was?

MfG
Fabian

JoltinJoe 9. Jul 2010 06:00

AW: TThread - Sleep
 
Die 100 habe ich frei aus der Luft gegriffen, wieviele es werden ist noch nicht bekannt, denke mal um die 20 Threads.

Ich seh da auch kein Problem ;) Aber wie gesagt, es funktioniert nicht... (Habs auch schon mit 3, 10, 20 Threads versucht)

ChrisE 9. Jul 2010 07:06

AW: TThread - Sleep
 
Hallo JoltinJoe,

also soweit ich das in dem gekürzten Beispiel aus dem letzten Post mit den Sourcen sehen kann, macht jeder Thread hauptsächlich arbeit in der Zeit des MainThreads (Synchronize). Natürlich ist das ein gekürztes Beispiel, aber dieses Beispiel zeigt seht gut, dass Threads nicht immer die Lösung sind.

Ich würde versuchen, den Ansatz von xZise zu verfolgen und ResetCondition und HighCondition durch CriticalSections ab zu sichern. Das könnte etwas bringen.
Des weiteren würde ich versuchen WriteResults ebenso in einen Speicherbereich zu schreiben, denn du mit einer CriticalSection absichern kannst und dann deine Application z.B. per PostMessage darüber informierst, dass in dem Speicher etwas liegt, dass man auf der Oberfläche aus geben sollte.

Delphi-Quellcode:
TMyThreadContainer = class
private
  FCSFetchCount: TCriticalSection;
  FCSResults: TCriticalSection;
  FFetchCount: Integer;
public
  procedure Start(AInfoFrom: TForm);
  procedure HighCondition;
  procedure ResetCondition;
published
  property FetchCount: Integer read GetFetchCount write SetFetchCount;
end;

TMyOwnThread = class(TThread)
private
  FOwnerContainer: TMyThreadContainer;
//
public
  property OwnerContainer: TMyThreadContainer read FOwnerContainer write FOwnerContainer;

//...

function TMyThreadContainer.GetFetchCount: Integer;
begin
  FCSFetchcondition.Enter;
  try
    result:=FFetchCount;
  finally
    FCSFetchCount.Leave;
  end;
end;

procedure TMyThreadContainer.SetFetchCount(Value: Integer);
begin
  FCSFetchCount.Enter;
  try
    FFetchCount:=Value;
  finally
    FCSFetchCount.Leave;
  end;
end;

procedure TMyThreadContainer.HighCondition;
begin
  FetchCount := FetchCount +1;
end;

procedure TMyThreadContainer.ResetCondition;
begin
  FetchCount := 0;
end;

// ....

procedure TMyOwnThread.Execute;
begin
  while not Terminated do
  begin
    FOwnerContainer.HighCondition;
    if FOwnerContainer.FetchCount>50 then
    begin
      Sleep(10000);
      FOwnerContainer.ResetCondition;
    end;
    FOwnerContainer.WriteResults('bla bla');
  end;
end;
Wie gesagt, hier nur grob das Beispiel. Aber WriteResults kannst du noch absichern durch eine CS und dort halt das InfoForm per PostMessage informieren, dass es Ergebnisse zum abholen gibt. Der Container kann dann auch das Starten und ggf. auch das Abbrechen der Threads übernehmen. Das liegt dann an Dir :-)

Greez, Chris

JoltinJoe 9. Jul 2010 07:46

AW: TThread - Sleep
 
Hm das sieht schonmal interessant aus aber dann stellt sich trotzdem die Frage warum Sleep unter den Umständen nicht funktioniert. Ohne Sleep werden die Aufgaben parallel und ohne Probleme ausgeführt. Also sollte Synchronize eigentlich die richtige Wahl gewesen sein ?

Sir Rufo 9. Jul 2010 08:50

AW: TThread - Sleep
 
Nein, Synchronize bremst einen Thread immer aus.
Eine CriticalSection ist da wesentlich besser, vor allem weil beim Setzen eines Wertes ein Synchronize völlig überflüssig ist.
Wenn du mit deinem Fahrrad fährst, hälst du auch nicht an, nur um dich am Kopf zu kratzen.

Ich versuche immer ein Synchronize zu vermeiden und arbeite mit CriticalSections und PostMessage oder Polling. Dadurch bleibt der Thread autonom und performant.

Und ein Sleep in einem Thread geht dann auch :-)

JoltinJoe 9. Jul 2010 08:53

AW: TThread - Sleep
 
Gut dann werd ich das aufjedenfall probieren ! Bleibt trotzdem die Frage warum Sleep mit Synchronize nicht funktionert :)

ChrisE 9. Jul 2010 08:59

AW: TThread - Sleep
 
Hallo JoltinJoe,

wie Sir Rufo schon gesagt hat ist da ein großer Unterschied. Synchronize sorgt quasi dafür, dass die Methode durch den Haupt-Thread ausgeführt wird. Eine CriticalSection sorgt nur dafür, dass dieser Bereich nur von einem Thread gleichzeitig "betreten" wird.

Aber du hast recht, mir will es gerade auch noch nicht in den Kopf, warum Sleep in der execute-Methode nicht funktioniert bzw. den Haupt-Thread zum Stillstand bringt.

Greez, Chris

JoltinJoe 9. Jul 2010 10:04

AW: TThread - Sleep
 
Die CriticalSection ist klar, jedoch habe ich jetzt noch nicht verstanden wie ich die Daten dann aufs Formular bringe. PostMessage ?! :pale:


PS: Mal was anderes, warum wird häufig ein führendes F vor Variablen etc genutzt ?

ChrisE 9. Jul 2010 10:23

AW: TThread - Sleep
 
Delphi-Quellcode:
TMyThreadContainer = class
private
  FCSResults: TCriticalSection;
  FResults: TStringList;
  FInfoHandle: HWnd;
  FInfoMessage: Cardinal;
  //...
public
  procedure Start(AInfoFormHandle: Handle; AMessage: Cardinal);
  procedure AddResult(AString: string);
  function HasMoreResults: Boolean;
  function GetResult: string;
  //...
end;

//...

procedure TMyThreadContainer.Start(AInfoFormHandle: HWnd; AMessage: Cardinal);
begin
  // ...
  FInfoHandle := AInfoFormHandle;
  FInfoMessage := AMessage;
  // ...
end;

procedure TMyThreadContainer.AddResult(AString: string);
begin
  FCSResults.Enter;
  try
    FResults.Add(AString); // immer oben drauf
  finally
    FResults.Leave;
  end;
  // Sperrung der Section so kurz wie möglich halten
  PostMessage(FInfoHandle, FInfoMessage, 0, 0);
end;

procedure TMyThreadContainer.HasMoreResults: Boolean;
begin
  FCSResults.Enter;
  try
    result := FResults.Count > 0;
  finally
    FResults.Leave;
  end;
end;

procedure TMyThreadContainer.GetResult: string;
begin
  FCSResults.Enter;
  try
    result := FResults[0];
    // UPS -> hier noch löschen :-)
    FResults.Delete(0);
  finally
    FResults.Leave;
  end;
end;

//....
const WM_NEW_RESULTS = WM_USER +1;


type
TForm1 = class(TForm)
  procedure WMNewResults(msg: TMessage);message WM_NEW_RESULTS;
//...
end;

procedure TForm1.DoStart;
begin
  // ....
  MyThreadContainer.Start(Self.Handle, WM_NEW_RESULTS);

  // ....
end;

procedure TForm1.WMNewResults(msg: TMesssage);
begin
  Listbox1.Items.BeginUpdate;
  try
    while MyThreadContainer.HasMoreResults do
    begin
      ListBox1.Items.Add(MyThreadContainer.GetResult);
    end;
  finally
    ListBox1.Items.EndUpdate;
  end;
end;
Ungetestet :-)

Greez, Chris

xZise 9. Jul 2010 10:34

AW: TThread - Sleep
 
Moin,
Zitat:

Zitat von JoltinJoe (Beitrag 1034451)
Die CriticalSection ist klar, jedoch habe ich jetzt noch nicht verstanden wie ich die Daten dann aufs Formular bringe. PostMessage ?! :pale: [...]

Du sendest einfach eine Nachricht an das Hauptformular und damit an den Hauptthread.

Ich selber mache da auch gerne ein synchronisiertes Event draus.

Zitat:

Zitat von JoltinJoe (Beitrag 1034451)
[...]PS: Mal was anderes, warum wird häufig ein führendes F vor Variablen etc genutzt ?

Bei private Attributen eines Objekts verwendet man gerne als Präfix das große F, damit man mit einer gleich lautenden Property (außer dem F) zugreifen kann (z.B.). Das F steht dabei für Field.

MfG
Fabian

JoltinJoe 10. Jul 2010 14:51

AW: TThread - Sleep
 
*PUSH*

Hat jemand schon eine Lösung warum "Sleep" und "Synchronize" nicht gut zusammen spielen ?


bYe

ChrisE 12. Jul 2010 07:04

AW: TThread - Sleep
 
Hallo JoltinJoe,

du hast ja schon aufgezeigt bekommen, wie du Dein Problem lösen kannst. Bisher habe ich keine Probleme mit Synchronize und Sleep gehabt, wenn ich sie richtig "miteinander" verwendet habe.

Du könntest ja einfach mal ein Demoprojekt zusammenbauen, bei dem Du zeigst, dass dieses Problem in Deiner Verwendung auftritt. Dann könnte man es genauer heraus bekommen.

Greez, Chris

w4rheart 16. Dez 2010 21:32

AW: TThread - Sleep
 
Hallo zusammen ;)

Tut mir Leid, dass ich diesen alten Thread nochmal ausgrabe, aber ich abe ein ähnliches Problem mit Theads und sleep.
Ich habe versucht den Beispielcode der hier geschrieben wurde umzusetzen, jedoch ohne Erfolg.

Ich möchte lediglich einen neuen Thread aufmachen, dort 5 sek warten und danach einige prozeduren ausführen.
Könnte mir jemand erklären wie das geht?

Ich werde aus diesem ganzen CriticalSection,highcontainer etc. nich wirklich schlau :lol:

Hat evtl. jemand eine fertige klasse für mich?
Was genau muss ich bei MyThread.execute ändern?

Wäre super, wenn jemand mir weiterhelfen könnte

MfG
w4rheart

ChrisE 17. Dez 2010 06:25

AW: TThread - Sleep
 
Hallo w4rheart,
Zitat:

Zitat von w4rheart (Beitrag 1068990)
Ich möchte lediglich einen neuen Thread aufmachen, dort 5 sek warten und danach einige prozeduren ausführen.
Könnte mir jemand erklären wie das geht?

ich würde folgendes vorschlagen:
Delphi-Quellcode:
procedure TMyThread2.Execute;
begin
  // 5 Sekunden Warten
  Sleep(5000);
  // Ein paar Prozeduren ausführen
  Self.Mehtode1;
  Self.Methode2;
end;
Ich denke aber das das nicht dein Problem lösen wird. Bei Threads bedarf es u.U. etwas mehr an wissen rund um das Problem. Wichtig ist z.B. auch, dass die in der Execute-Methode eines Threads nicht auf die VCL (Formulare / Visuelle Komponenten) zugreifst. D.h. eben auch nicht auf Methoden zugreifst, die das dann machen ;-)

Gruß, Chris

w4rheart 17. Dez 2010 14:31

AW: TThread - Sleep
 
Hallo ChisE, danke für deine Antwort.
ALso auf Visel Komponenten und der gleichen greife ich nicht zu.
Das ganze ist ein Netzwerkspiel, die Prozedur befindet sich auf dem Server.
Deser soll halt, wenn wein ein Spieler gestorben ist diesen nach 5 sekunden wiederbeleben.
-> Daher halt die Idee mit Threads, weil der halt 5 sek warten soll, und mit sleep sich das ganze programm aufhängt...

Hättest du da evtl. eine praktikable Lösung?

MfG

rollstuhlfahrer 17. Dez 2010 15:00

AW: TThread - Sleep
 
Timer? - Also ich denke mal nicht, dass diese 5 Sekunden exakt genaustens eingehalten werden müssen. +- 10 Millisekunden (durch den Timer) dürften immer noch akzeptabel sein.

Bernhard


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:40 Uhr.

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