Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Endlosschleife + WarteFunktion ohne Programm zu blockieren (https://www.delphipraxis.net/105185-endlosschleife-wartefunktion-ohne-programm-zu-blockieren.html)

.chicken 17. Dez 2007 17:58


Endlosschleife + WarteFunktion ohne Programm zu blockieren
 
Ok, ich hoffe der Threadtitel ist einigermassen aussagekräftig. Mein Problem ist folgendes:
Ich gehe in einem Programm eine XML Datei nach der Reihe durch und je nach nodeName führe ich eine gewissen Prozedur aus. Durchgehen tue ich die XML in einer Endlosschleife, die unterbrochen wird, wenn ein unbekannter, bzw ein exit-Befehl in der XML auftaucht.

So, taucht zB der nodeName "sentence" auf, dann wird die Prozedur ProcessSentence aufgerufen. Hier wird der Text von "sentence" in ein Array gespeichert und danach das Event OnChange meiner eigenen Klasse ausgelöst. Diesem Event habe ich in meiner MainForm dann zugewiesen, dass er die MainForm neu malt, wobei das Array aus meiner Klasse geschrieben werden soll. So, direkt nach dem Aufruf des Events, rufe icih die Funktion Delay auf, die verhindern soll, dass direkt das nächste Array Element aufgerufen wird.

Delphi-Quellcode:
procedure TDialogClass.Delay(msecs: LongInt);
var
  Start, Stop: LongInt;
begin
  Start := GetTickCount;
  repeat
    Stop := GetTickCount;
    Application.ProcessMessages;
  until Stop - Start >= msecs;
end;
So, in meiner Endlosschleife habe ich auch Application.ProcessMessages stehn, jedoch wird das Events und somit das OnPaint Ereignis nicht ausgelöst, und der Text nicht ausgegeben. Was ist der Fehler? Wie mache ich sonst eine Funktion die das vorranschreiten der Endlosschleife verhindert, bzw wie verhinder ich dasas die Endlosschleife das Programm blockiert (weiss nicht was von beidem oder ob beides davon zutrifft)!

Hoffe ihr versteht was ich meine und könnt mir helfen!

Zacherl 17. Dez 2007 18:06

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Lager das Ganze doch in einen Extra Thread aus.

.chicken 17. Dez 2007 18:11

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Joa, was Threads sind weiss ich nicht, aber damit lassen sich solche Probleme lösen? Dann würde ich mich darüber genauer informieren. Wenn jemand ein gutes Tutorial zur Hand hat, gerne her damit ^^

Edit: Fast das Danke vergessen ^^ also, Dankesehr ^^

DeddyH 17. Dez 2007 18:14

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Schau mal in die Demos, da ist auch eins zu Threads dabei.

[edit] Eine Demo meinte ich damit, kein Tutorial :oops: [/edit]

.chicken 17. Dez 2007 18:36

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Delphi Demos oder was? Wo find ich die? :oops:

DeddyH 17. Dez 2007 18:38

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Bei mir stehen die unter {Delphi}\Demos, die zu Threads also unter {Delphi}\Demos\Threads

.chicken 17. Dez 2007 18:39

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Hab ich nicht den Ordner, habe die Delphi7SE !?

DeddyH 17. Dez 2007 18:40

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Meinst Du PE? Dann kann es sein, dass die nicht dabei sind.

.chicken 17. Dez 2007 18:43

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Ne, die SecondEdition.

DeddyH 17. Dez 2007 18:44

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Sry, sagt mir jetzt nichts. Ist das eine Personal?

.chicken 17. Dez 2007 18:46

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
WEiss ich nicht genau, aber ist ja egal ich habe hier im Forum zwei Tutorials gefunden. Aber das ist ja meeeeega umfangreich!? o.O
Das wird ja ne heidenArbeit isch da durchzuforsten!

sirius 17. Dez 2007 18:54

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Nee, wieso.
1. Ansatz ist einfach eine Klasse von TThread ableiten und dann die Execute-Methode überschreiben. Und darin legst du den Code des Threads. Fertig. Musst natürlich beachten, dass du jetzt nicht einfach so kreuz und quer auf Variablen zugreifen kannst.

.chicken 17. Dez 2007 19:13

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Ich hab diesen Wälzer gefunden ^^
http://www.michael-puff.de/Developer...mit_Delphi.pdf
Habe mich shcon bisl durchgeforstet aber ist für imch nicht so einfach zu verstehen. Habe aber nun schon ein grobes Verständnis was passiert und was nicht passieren sollte ^^

Wenn ich jetzt noch ein simples Tut hätte, dass sich nur damit beschäftigt wie man das benutzt, dann würd das sicher was werden ^^

Edit: Achso, dann lager ich am besten meine Endlosschleife in einen Thread aus und die verarbeitung der nodeNames oder? Weil ich da dann ja noch die Wartezeit mit dem Thread erledigen könnte!?

Zacherl 17. Dez 2007 19:25

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Benutze doch einfach CreateThread oder BeginThread :P Dann kannst du in deinem Thread die Arbeiten durchführen und dein Programm friert trotzdem nichtein.

.chicken 17. Dez 2007 19:30

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Zitat:

Zitat von Zacherl
Benutze doch einfach CreateThread oder BeginThread :P Dann kannst du in deinem Thread die Arbeiten durchführen und dein Programm friert trotzdem nichtein.

Da wurschtel ich mich doch grade durch Meister ^^
Danke trotzdem ;-)

.chicken 18. Dez 2007 20:26

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ok, ich raff das mit den Threads einfach noch nicht. Ich würde mich sehr freuen, wenn ihr euch mal meine Unit ansehen würdet und mir ein paar Anstöße geben könntet! Möchte keinen vollständigen Code, denn ich möchte verstehen was ich tue ;-)

So, ich weiss einfach nicht wie ich da die Threads einbaun soll. Soll ich beim DialogStart einen Thread erstellen, der dann ProfceedDialog aufruft? Wie mache ich das? Hierbei sagt er mir immer
Delphi-Quellcode:
BeginThread(nil, 0, TFNThreadStartRoutine(@ProceedDialog), nil, 0, ThreadID);
"Variable Required udn zeigt auf das @ProceedDialog.

Ich habe keinen Plan wie ich das nun realisieren soll, und die Parameter der BeginThread Funktion verstehe ich auch nicht so recht, bin aus den Tut Beschreibungen net recht schlau geworden!

Edit: Achso, hilfreich wäre vielleicht zu wissen, dass das ganze als DialogSystem in einem Adventure genutzt werden soll!

peschai 19. Dez 2007 07:12

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Hallo,
Um auf das eigentliche Problem zurückzukommen:
Wenn du ein OnPaint provozieren möchtest, so rufe auf:
Delphi-Quellcode:
<Komponente>.Invalidate
Damit wird das Betriebssystem bei der nächsten Gelegenheit ein repaint veranlassen ...

sirius 19. Dez 2007 08:40

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
ProceedDialog muss eine Funktion sein mit folgender Deklaration:
Delphi-Quellcode:
function ProceedDialog(param:pointer):integer;
Beachte, dass dies keine Methode ist, also nicht innerhalb einer Klasse sein darf.

Ausserdem darfst du in einem Thread nicht auf globale Variablen zugreifen, bzw. auf Variablen, die auch der Main-Thread gleichzeitig benutzen könnte. Wenn dies zwingend notwendig wird, muss man eben synchronisieren.

Du benutzt jetzt BeginThread. Warum nimmst du nicht eine Ableitung der Klasse TThread? Das ist für den Anfang viel einfacher. Vor allem sind die Änderungen, die du machn müsstest überschaubarer, wenn du die Klasse TDialogclass von TThread ableitest.

.chicken 19. Dez 2007 10:57

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Ok, danke euch beiden!
Sirius, kannst du das etwas genauer erklären? Also ich leite die DialogUnit von TThread ab...sobald sie erzeugt wird ist das dann ein eigener Thread? Dann muss ich aber trotzdem noch mit den Variablen aufpassen oder? Also habe was von Critical Sections gelesen, das müsste sich dafür doch eignen oder?

D.h. die einzige Änderung die ich machen müsste, wäre die Klasse von TThread abzuleiten und dann kann ich quasi alles so lassen, abgesehn davon dass ich mit den globalen Variablen aufpassen muss?

sirius 19. Dez 2007 11:02

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Liste der Anhänge anzeigen (Anzahl: 1)
Fast. Ich sehe halt den Rest des Programms nicht (besonders, wann du Methoden/Eigenschaften von der Klasse verwendest). Und kann nicht sagen, ob es alles ist.
Und zudem musst du dann die Execute-Methode anlegen/überschreiben. Die wird nämlich ausgeführt.
Alle Parameter die du brauchst übergibst du im Constructor. Wenn du nachher noch Werte zwischen den Threads austauschen willst, dann würde ich dir erstmal zu "synchronize" raten (ist für den Anfang am einfachsten und dürfte bei dir auch ausreichen; da brauchst du dich mit CriticalSections noch nicht zu beschäftigen). Kann ich dir besser an einem Beispiel erklären, wenn du eins hast.

Edit: Anhang angefügt
Ich habe mal die Änderungen, die ich jetzt gesehen habe gemacht. Ob das jetzt alles richtig ist, weis ich nicht, da ich den Rest des Programmes nicht kenne.
GEdacht ist es jetzt so, dass du das Objekt instanzierst und damit läuft der Thread gleich los (außer die Exception wird geworfen)und ruft irgendwann mal das TOnChange-Ereignis auf. Und genau darin bzw. nur darin darfst du dir den vollen Zugriff auf dein Objekt erlauben.

.chicken 19. Dez 2007 11:37

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Also genutzt wird die Unit von aussen insofern, dass sie gestartet wird und sobald das Ereignis OnChange auftritt, werden von aussen die Sentences und Options angezeigt, die in den Arrays sind.

Delphi-Quellcode:
Und zudem musst du dann die Execute-Methode anlegen/überschreiben. Die wird nämlich ausgeführt.
Wie mach ich das? Verstehe noch net ganz was du damit meinst! ^^

sirius 19. Dez 2007 11:41

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
siehe edit :mrgreen:

Edit: Ach und zum steuern des Threads von aussen gibt es die Methoden:
-suspend (anhalten)
-resume (fortsetzen)
-terminate (abbrechen, dadurch wird eben terminated gesetzt)

.chicken 19. Dez 2007 12:01

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Danke sehe ich mir die Tage an, muss nun wech ;-)

.chicken 21. Dez 2007 13:25

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Ok, das ist soweit ja relativ einfach, also Execute startet den Thread einfach und am Ende von Execute wird er wieder beendet? Dh ich muss für jeden Dialog den ich aufrufe das ganze neu Createn oder?

Die Sache ist jetzt noch, ich kann ja so nur im OnChange Ereignis darauf zugreifen, ich muss aber jedes mal wenn die Form, die die Unit einbindet gepainted wird, darauf zugreifen können, also nur die Variablen abrufen, nicht ändern! Geht das einfach oder muss ihc in der Form dann neue Variablen machen, die im OnChange geändert werden? Fänd ich etwas unpraktisch!

Soweit aber schonmal ein FETTES DANKE, dafür dass du dir die Mühe gemacht hast dir das anzusehn und es zu ändern :) Super nett ;-)

.chicken 25. Dez 2007 21:29

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Würde mir meinen letzten Post wohl nochmal wer beantwortet bitte? :angel: :dp: :-D Frohe Weihnachten ;-)

Opa 26. Dez 2007 03:02

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Ohne Test, so aus dem Kopf. Die Werte aggf. ans Formular senden!!!
Code:
unit MyThread;
interface
uses
  Windows,Classes,SysUtils,ComCtrls)

  TMyThread = class(TThread)
    private
      AHandle   : THandle;
    protected
       procedure Execute;override;
    public
    published
    protected
    public
      constructor Create(Handle:THandle);virtual;
      destructor Destroy;override;
    published
  end;
implementation
{Type-TDriveThread-Anfang******************************************************}

{Protected-TDriveThread-Anfang*************************************************}
procedure TMyThread.Execute;
var
  I : intger;
begin
  inherited;
  I := 0;
  SendMessage(AHandle,WM_USER+10,0,0); // Für Senden für Meldungen
  while GetAsyncKeystate(VK_ESCAPE) <> 0 do//abbruch wenn ESC-Taste
  begin
    SendMessage(AHandle,WM_USER+11,0,I); //
    inc(I);
  end;
  SendMessage(AHandle,WM_USER+12,0,0);
end;
{Protected-TDriveThread-Ende***************************************************}

{Public-TDriveThread-Anfang****************************************************}
constructor TMyThread.Create(Handle:THandle);
begin
  inherited Create(true);
  AHandle  := Handle;
  Priority := tpLowest;//Die Eigenschaft Priority gibt die Priorität des Thread an.
                        // Je nach Bedarf kann eine höhere oder niedrigere Priorität zugeordnet werden.
end;
//------------------------------------------------------------------------------
destructor TMyThread.Destroy;
begin
  inherited;
end;
{Public-TDriveThread-Ende******************************************************}
{Type-TDriveThread-Ende********************************************************}

uses
  MyThread;
{in Haupform}
private
  FMyThread : TMyThread;
  procedure WM_USER10(var Msg: TMessage); message WM_USER+10;
  procedure WM_USER11(var Msg: TMessage); message WM_USER+11;
  procedure WM_USER12(var Msg: TMessage); message WM_USER+12;

procedure TMain.FormDestroy(Sender: TObject);
begin
  FreeAndNil(FProgressbarThread);
end;

procedure TMain.Button1Click(Sender: TObject);
begin
  FMyThread := TMyThread.Create(Handle);
  FMyThread.Resume;
end;

procedure TMain.WM_USER10(var Msg: TMessage);
begin
  Label1.Caption := 'Start';
end;

procedure TMain.WM_USER11(var Msg: TMessage);
begin
  Label2.Caption := intToStr(Msg.LParam);
end;

procedure TMain.WM_USER11(var Msg: TMessage);
begin
  Label3.Caption := 'Fertig';
end;
MFG

.chicken 26. Dez 2007 11:46

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Finds toll dass du duir soviel Mühe gemacht hast, danke aber mit fertigem Code kann ich recht wenig anfangen. Ich hätte lieber einen kleinen Denkanstoß gehabt. Was muss ich machen damit ich dauerhaft bestimmte Variablen von aussen lesen kann?

Wie wärs mit einer onRead-Procedure, die während der Ausgabe den Thread pausiert!?

Opa 26. Dez 2007 12:46

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Zitat:

Wie wärs mit einer onRead-Procedure, die während der Ausgabe den Thread pausiert!?
Komm darauf an ob ich richtig verstanden habe:
Wenn der Thread läuft soll irgend was nicht passieren? Du wenn der Thread zuende ist soll es weiter gehen?
Wo ist das Problem!
SendMessage(AHandle,WM_USER+10,0,0); Meldung das der Thread gestartet wurde, er sagt dieses dem Hauptformular. SendMessage(AHandle,WM_USER+12,0,0), macht das gleiche wenn Thread fertig.


procedure WM_USER10(var Msg: TMessage);
begin
FtuNix := true;
end;
procedure WM_USER12(var Msg: TMessage);
begin
FtuNix := false;
end;

SendMessage(AHandle,WM_USER+11,0,0), sagt dem Hauptformular das er arbeitet.

Wenn es das nicht ist was du gefragt hast: Dann mal erklären was du mit onRead meinst.

Mfg

.chicken 26. Dez 2007 13:00

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Nene, also ich habein meiner DialogUnit zwei ein paar Variablen und Arrays, auf die das Formular jederzeit zugreifen können soll, damit sie dort gezeichnet werden. Ich habe ein OnChange-Event, in diesem Event kann die Form schon auf die Variablen zugreifen, ich möchte aber dass die Form das immer kann.

Dazu könnte ich einfach im OnChange Event die Variablen an das Formular übergeben und sie da speichern, bis ein neues OnChange Event auftritt. Das ist mir aber eigentlich zu umständlich und "unsauber" (warum Variablen doppelt speichern...).

Also könnte ich nicht einfach die Variablen in meiner Dialog Unit als Property erstellen und dann eine ReadFunktion für sie schreiben in der der Thread pausiert wird, dann die Variable zurückgegeben und dann der Thread wieder gestartet wird oder so?
Oder gibts da ne andere, bessere Lösung?

Danke schonmal für die Hilfe!

sirius 26. Dez 2007 23:03

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
:gruebel: ich dachte ich hätte schon darauf geantwortet.

Mir fallen drei Möglichkeiten ein:
1. Die Werte zwischenspeichern. Du nennst es zwar unsauber, ist aber genau das um Threads sauber zu trennen und nich kreuz und quer auf Variablen zuzugreifen
2. Wenn sich die Werte sowieso selten ändern, könnte man hier mal über "Critical Sections" (TCriticalSection) nachdenken. Das sind quasi verschiedene Codeabschnitte die irgendwo in beiden Threads liegen (können) und wo du sicherstellen kannst, dass sich nur ein Thread zu einem Zeitpunkt in einem dieser Abschnitte befindet (und eben alle anderen dadurch "blockiert" sind). Ein zweiter Thread müsste, wenn er auch in so einen Abschnitt wöllte, erstmal warten. Dadurch erreichst du eine gewisse Synchronisation. Solche Codeabschnitte sind dann eben der gemeinsame Datenzugriff.
3. Message an den Thread schicken. Dürfte für dich irrelevant sein, denn dann müsste man erstmal ein Windohandle erzeugen (da ist 2. einfacher)
4. Thread mittels suspend anhalten, Variablen lesen und dann resume aufrufen. Finde ich unschön, auch wenns am einfachsten aussieht

.chicken 27. Dez 2007 00:10

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Wenn du sagst du findest vier unschön, was findest du am schönsten? 1? Ist das nicht unelegant, doppelte Variablen zu haben?

sirius 27. Dez 2007 09:58

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Ein Thread ständig anzuhalten ist eben nicht im Sinne des Erfinders. Aber je nachdem, wie du es im Programm benötigst, kannst du es ja einsetzen.

Aber versuchs mal mit TCriticalSection. Du erstellst ein Objekt davon im Main-Thread und übergibst es auch an den Thread (am besten über den Constructor) und immer bevor du in die kritische Region kommst (wo du auf eben diese Variablen zugreifst) rufst du IMHO CriticalSection.Enter auf und danach wieder leave. Wichtig ist, dass es dasselbe Objekt ist.

.chicken 27. Dez 2007 10:22

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Ok, danke darüber informier ich mich dann genauer ;-)

.chicken 29. Dez 2007 13:47

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ok, ich habe ein Problem! Ich kriege immer nen Abstract Error! Ich habs nun erstmal zum testen so gemacht, dass ich die Variablen in meiner FormUnit nochmal speichere. Ich hänge alles mal dran.

Ich weiss nicht worans liegt, irgendwie habe ich dass Gefühl dass Execute auch nicht ausgeführt wird, aber vll täusche ich mich auch.

Klickt einfach im Programm oben auf Dialog und dann auf Testen. Normalerweise sollte dann rechts in der Paintbox der Dialog abgespielt werden. Zumindest die Funktionen die shcon funktionieren. Aber ich krieg immer den Error :-\

sirius 29. Dez 2007 13:52

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
execute wird nicht ausgeführt, da du die Methode überschreiben musst.

Testen kann ich den Code nicht, da mir min. eine Unit fehlt, aber ich hab noch etwas gefunden:
Delphi-Quellcode:
for i := 0 to length(Dialogs.SentenceArray) - 1 do
begin
  SetLength(LocalSentenceArray, length(LocalSentenceArray) + 1); //<----
  LocalSentenceArray[i] := Dialogs.SentenceArray[i];
end;
Du kopierst ja hier das Array. Und in einer Schleife sollte man die von mir markierte Zeile solange es geht vermeiden.
Das macht es ja auch:
Delphi-Quellcode:
SetLength(LocalSentenceArray, length(Dialogs.SentenceArray));
for i := 0 to high(Dialogs.SentenceArray) do
  LocalSentenceArray[i] := Dialogs.SentenceArray[i];

.chicken 29. Dez 2007 14:32

Re: Endlosschleife + WarteFunktion ohne Programm zu blockier
 
:wall: :wall: :wall:

Danke :angel: ^^


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:15 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