# Libnodave Anwendung schliessen



## Snoopy123123 (20 Juli 2009)

Wenn ich meine Libnodave Anwendung schliesse erzeugt die Komponente jedesmal eine unschöne exception. Ich nutze Delphi und setze in meiner OnCloseQuery "nodave.active:= false;"  Was muss ich nich tun damit damit keine Exception bei OnClose erzeugt wird ?!?


----------



## Human (21 Juli 2009)

Hab leider keine Glaskugel dabei... kannst du vielleicht noch mitteilen was für eine "unschöne Exception" das ist?

Rufst du deine Komponente in einem Thread auf, was machst du sonst noch damit usw.?


----------



## Rainer Hönle (21 Juli 2009)

Human schrieb:


> Hab leider keine Glaskugel dabei...


Bist Du immer noch im Amerika? Und hast Deine Kugel daheim gelassen?


----------



## Human (21 Juli 2009)

Ne, bin seit Freitag wieder zurück, aber die Glaskugel hab ich daheim gelassen!


----------



## Ralle (21 Juli 2009)

Na ja, in der OnCloseQuery ist das nicht immer glücklich untergebracht. Man muß ja der Applikation dann auch noch die Zeit einräumen, die Verbindung zu trennen usw. Ich würde testweise mal versuchen einen Button zu nutzen, der nodave inaktiv setzt und dann die Applikation schließen. Wenn das problemlos geht, dann mal eine Wartezeit einbauen oder noch besser nachsehen, ob die Nodavekomponente irgend etwas zurück liefert, was einem anzeigt, daß sie fertig ist!


----------



## Snoopy123123 (21 Juli 2009)

Human schrieb:


> Ne, bin seit Freitag wieder zurück, aber die Glaskugel hab ich daheim gelassen!



Wie ohne Glaskugel auf die Baustelle ?! Ist ja wie en Bäcker ohne Mehl....

Ne aus der Exception Meldung denke ich kann man nicht schlau werden, hier heisst es nur exception in ***.exe aufgetreten. Ich hab mal den Assemblercode der Unterbrechungsstelle angehangen. Vielleicht kann ia jemand hier sowas lesen, ich nicht :-(

Dachte es gäbe vielleicht irgend etwas das ich in der Komponente noch abschalten muss bevor ich die Anwendung terminiere.

@Ralle:

Habe da schon meherer sekunden Zeit eingeräumt bevor endgültig geschlossen wird. Mit dem Button passiert mir das gleiche, jedoch erst wenn die Anwendung schliesse :-(


----------



## Rainer Hönle (21 Juli 2009)

Bei Delphi kenne ich mich jetzt nicht wirklich aus. Aus meiner Erfahrung mit Billisoft weiß ich, dass bei entsprechenden Terminierungs-Ergeignissen schon alle anderen Threads tot sind und somit nicht mehr reagieren können. 
Was passiert eigentlich im OnClose sonst noch? Was zeigt der Debugger an, wenn weitergesteppt wird bis wieder Quellcode sichtbar ist?


----------



## Human (21 Juli 2009)

[GLASKUGEL]
Ich denke jetzt einmal, dass du deine NoDave-Komponente in einem Thread benutzt???

Wenn das der Fall sein sollte: Erst den Thread beenden, dann die Verbindungen beenden und dann die Anwendung schließen lassen. Ich würde das auch nicht umbedingt in das OnCloseQuery reinbauen, sondern in das OnDestroy:


```
procedure OnDestroy(Sender: TObject);
begin
  Thread.Terminate;
  repeat
    Application.ProcessMessages;
  until Thread.Beendet;
  NoDave1.Active := FALSE;
end;
```
 
Dein Thread:


```
procedure TMyThread.Execute;
begin
  Beendet := FALSE;
  repeat
    DieUndDas;
  until Terminated;
  Beendet := TRUE;
end;
```
 
Und dann dürfte eigentlich nichts mehr schiefgehen! 

[EDIT]
Falls du noch irgendwo einen Timer hast, in dem du die Komponente auch noch drinnen hast, dann solltest du den auch vor dem Beenden der Verbindung auf Eis legen mit Enabled := FALSE!!!
[/EDIT]
[/GLASKUGEL]


----------



## Ralle (21 Juli 2009)

Mit Threads in Delphi muß man immer etwas herumprobieren. Ich hatte da so einige komische Ergebnisse, die ich mir nicht genau erklären konnte. Die Komponente selbst nutze ich nicht, aber ich meine, die macht intern einen eigenen Thread auf, um die Daten zu holen. Es wäre auch mal zu probieren, dem eigenen Thread (so vorhanden) ein Nil zuzuweisen, nach dem beenden und die Komponente vor dem schließen der Applikation komplett zu beenden, also mit Destroy oder einer ähnlichen Methode, die zur Verfügung steht. Mit solchen Exceptions hab ich auch lange gekämpft, da muß man leider wirklich ein wenig rumprobieren.


----------



## Human (21 Juli 2009)

Die NoDave-Komponente bekommt von mir niemals mehr ein Free geben beim Beenden, irgendwie hat es mir meine Programme auch immer voll mit Fehlermeldungen, das lass ich deshalb lieber Windwos erledigen!


----------



## Snoopy123123 (21 Juli 2009)

na im moment habe ich keine threads sondern nur einen timer die die nodaveread aufrufe enthält. 

Beim schliessen disable ich den Timer, warte dann 1 Sekunde und setze dann die nodave.active:= false !

dann warte ich nochmal ne sekunde und dann wird die Appliaction geschlossen....

Klar terminiert Windows die Anwendung, aber das ist ja nicht im sinne des entwicklers, oder ?


----------



## Ralle (21 Juli 2009)

Es ist doch ein Delphi-Beispiel bei Libnodave und er Komponente dabei oder? Dieses Beispiel bringt keine Exception beim Schließen. Vielleicht hilft es, sich mal anzusehen, wie das dort gemacht wurde.


----------



## Snoopy123123 (21 Juli 2009)

dort wird auch nur 
nodave.active:= false gesetzt !

Sonst ueberhaupt nichts ! Allerdings wird dort auch mit dem OnRead Ereignis der Komponente gearbeitet.


----------



## Question_mark (21 Juli 2009)

*snoopy, Du arbeitest doch nicht in einer Garagenfirma ...*

Hallo,

@snoppy123123 :

Was meinst Du wohl, warum ich damals bei unserem gemeinsamen Projekt nicht die kostenlose LibNoDave, sondern die kostenpflichtige AGLink 40 eingesetzt habe ???

In gewerblichen Projekten sollten ein paar Euro für eine professonielle Kommunikationsbibliothek wohl kein Thema sein. Oder man bezahlt in Form von Stress und unnötigem Aufwand an Zeit, Geld und Freizeit ...

Also investiere durch Deinen Arbeitgeber ein paar Euronen für eine AGLink Lizenz, Du hast in unserem Projekt doch genug Beispiele wie die Kommunikation SPS <--> PC mit Delphi ohne Probleme funktioniert. Und wenn Du dann noch Hilfe brauchst, meine email-Addy hast Du ja :s1:

Gruß

Question_mark


----------



## Snoopy123123 (22 Juli 2009)

Question_mark schrieb:


> Hallo,
> 
> @snoppy123123 :
> 
> ...




nee Fehlanzeige, das ist ne privatgeschichte und hat nichts mit der Firma zu tun. Das ganze Thema interessiert mich halt und seid unserem Project hab ich mich richtig in Delphi verliebt. 

PS: Wenn das mit dem Wirtschaftsboom so weiter geht dann könnte es aber bald noch ne Garagenfirma werden


----------



## Question_mark (22 Juli 2009)

*Free von Komponenten in Delphi*

Hallo,



			
				human schrieb:
			
		

> Die NoDave-Komponente bekommt von mir niemals mehr ein Free geben beim Beenden, irgendwie hat es mir meine Programme auch immer voll mit Fehlermeldungen, das lass ich deshalb lieber Windows erledigen!



Das kommt letztendlich doch darauf an, wie die NoDave Komponente erzeugt wird. Wenn Du die Komponente zur Entwurfszeit auf das Formular ziehst, wird die Komponente von diesem Formular automatisch erzeugt und auch beim Beenden (bzw. beim Destroy des Formulars) automatisch freigegeben. 
Delphi führt dieses "Free" automatisch durch, da diese Komponente in diesem speziellen Falle immer durch den "Parent" (also das Formular) freigegeben wird.
Wenn Du die nochmal durch ein "Free" zerstören willst, kann es dann manchmal im Gebälk von Windows mächtig knallen. 

Ein "Free" auf eine Delphi-Komponente darf nur gemacht werden, wenn diese durch deinen eigenen Programmcode dynamisch zur Laufzeit durch "Create" erzeugt wird. In diesem Fall kümmert sich Delphi nicht um die Freigabe, Du bist selber dafür verantwortlich diese Freigabe zu programmieren.

Gruß

Question_mark


----------



## Human (22 Juli 2009)

> Ein "Free" auf eine Delphi-Komponente darf nur gemacht werden, wenn diese durch deinen eigenen Programmcode dynamisch zur Laufzeit durch "Create" erzeugt wird. In diesem Fall kümmert sich Delphi nicht um die Freigabe, Du bist selber dafür verantwortlich diese Freigabe zu programmieren.


 
Normalerweise sollte man das auch machen, mache ich bei allen anderen Sachen auch, aber wenn ich meinen Prozess beende dann gibt das Windows auch ohne, dass ich das freigebe wieder frei!


----------



## Question_mark (22 Juli 2009)

*Libnodave*

Hallo,



			
				snoopy123123 schrieb:
			
		

> nee Fehlanzeige, das ist ne privatgeschichte und hat nichts mit der Firma zu tun.



Ok, ich konnte aus Deiner Frage nicht lesen, das hier eher privates Interesse besteht und das anders ausgelegt.

Gruß 

Question_mark


----------



## Snoopy123123 (22 Juli 2009)

Ich versteh es trotzdem nicht.

Hab die Anwendung jetzt so umgeschrieben das ich mit nem Button die komponente Active:= true oder Active:= false setze. 
Starte ich die Anwendung und schliesse sie ohne die Komponente Active zu setzen dann ist alles prima. Setze ich die Komponente auf Active:= true und dann wieder zurück auf false, und schliesse dann die Anwendung dann tritt eine Exception auf. 

@QuestionMark 
Ich habe die Komponente zur Entwurfszeit auf die Form gezogen und mache kein .free , habe aber auch schon mit destroy versucht die komponente bei on close zu entfernen und selbst dann bekomm ich die Exception.


----------



## Human (22 Juli 2009)

> Ich habe die Komponente zur Entwurfszeit auf die Form gezogen und mache kein .free , habe aber auch schon mit destroy versucht die komponente bei on close zu entfernen und selbst dann bekomm ich die Exception.


 
Das Destroy soll man normal nur nehmen, wenn es kein Free gibt!


----------



## Question_mark (22 Juli 2009)

*So einfach ist das nicht ...*

Hallo,



			
				human schrieb:
			
		

> aber wenn ich meinen Prozess beende dann gibt das Windows auch ohne, dass ich das freigebe wieder frei!



Ich höre jetzt zum ersten Mal, dass Windows so einen intelligenten "Garbage collector" eingebaut hat...
Google mal nach Eureka Log, dann lernst Du, wieviel Speicherlücken derartige Art der Programmierung erzeugen kann. Und vor allen Dingen hast Du dann ein Tool, mit dem man solche Speicherfresser aufspüren kann. 
Oder erzeuge mal ganz einfach in einer Applikation eine große Anzahl von Objekten dynamisch zur Laufzeit und beende Deine Applikation, ohne diese Objekte wieder freizugeben. Nach einer endlichen Anzahl von Ausführen Deiner Applikation kotzt Dir Windows entgegen, dass nicht mehr genug Speicher zur Verfügung steht 
Wenn so eine Applikation in einer 24/7 Laufzeit und in der Industrie stabil laufen soll, muss man schon etwas mehr Aufwand treiben als ein paar Komponenten auf ein Formular zu ziehen...

Gruß

Question_mark


----------



## Question_mark (22 Juli 2009)

*Noch einmal*

Hallo,



			
				human schrieb:
			
		

> Das Destroy soll man normal nur nehmen, wenn es kein Free gibt



Verdammt nochmal, willst Du mich nicht verstehen ?

Wenn die Komponente statisch durch ziehen auf das Parent Formular gezogen und automatisch erzeugt wird, darfst Du niemals ein "Free" oder auch "Destroy"  oder "FreeAndNil" auf diese Komponente anwenden, sonst knallt es meistens im Gebälk ...

Gruß

Question_mark


----------



## Human (22 Juli 2009)

> Verdammt nochmal, willst Du mich nicht verstehen ?
> 
> Wenn die Komponente statisch durch ziehen auf das Parent Formular gezogen und automatisch erzeugt wird, darfst Du niemals ein "Free" oder auch "Destroy" oder "FreeAndNil" auf diese Komponente anwenden, sonst knallt es meistens im Gebälk ...


Nö, warum denn? Hin und wieder muss man doch mal sein Forumla aufräumen! (siehe Anhang (Formular mit TEdit und wird mit dem Button mit Free freigegeben, bei mir knallt da nix!!!))

Und er hat niergends geschrieben wie er sie erstellt, ich erstell die immer zur Laufzeit...



> Ich höre jetzt zum ersten Mal, dass Windows so einen intelligenten "Garbage collector" eingebaut hat...


Bin ich mal davon ausgegangen, da Windows ja für jeden Prozess einen eigenen Speicherbereich anlegt, auf das "Normalerweise" (gibt ja proktische Funktionen, mit denen man doch auf andere Programme kommt) kein anderes Programm zugreifen kann, ich lass mich natürlich auch immer gern vom Gegenteil überzeugen!


----------



## Question_mark (22 Juli 2009)

*Delphi hat auch einen Debugger ...*

Hallo,



			
				snoopy123123 schrieb:
			
		

> versucht die komponente bei on close zu entfernen und selbst dann bekomm ich die Exception.



Natürlich, weil unter Umständen der Parent, also das Delphi Formular, die Komponente schon freigegeben hat. Das ist eher zufällig bedingt, da es davon abhängt, wann Delphi die Komponente freigibt. Das hängt schon davon ab, in welcher Reihenfolge die Formulare erzeugt werden. Ist also eher etwas "unpredictable".

Wenn Du die Komponente durch Ziehen auf das Formular erzeugt hast, dann unterlasse alle Versuche, diese irgendwann per Programmcode freizugeben. 
Damit hast Du schon mal eine Fehlerquelle ausgeschlossen.
Dennoch besteht offensichtlich ein Problem beim Beenden des Programms und mit der Freigabe von TLibNoDave. 
Das kann eigentlich nur zwei Ursachen haben :

1) Ein Fehler in der Komponente
2) Ein Fehler bei der Anwendung der Komponente durch den User

Ich halte den Punkt 2 für wahrscheinlicher, da es ja offensichtlich bei vielen anderen Anwendungen funktioniert.
Wird die Komponente eventuell aus einem TimerEvent oder einem Thread aufgerufen, der noch nicht beendet wurde, bevor der Parent der Komponente von Delphi freigegeben wurde. Dann ist auch die Komponente zerstört und dann gibt es die von Dir beschriebenen Exceptions. 
Und dann setze mal einen Breakpoint in das OnClose Event des ParentForm der Komponente. Und schaue mal, ob dort der Zeiger auf LibNoDave beim Eintritt in den Event schon auf NIL gebogen ist ...

Gruß

Question_mark


----------



## Question_mark (22 Juli 2009)

*Dann mach mal so weiter*

Hallo,



			
				human schrieb:
			
		

> Nö, warum denn? Hin und wieder muss man doch mal sein Forumla aufräumen! (siehe Anhang (Formular mit TEdit und wird mit dem Button mit Free freigegeben, bei mir knallt da nix!!!))
> 
> Und er hat niergends geschrieben wie er sie erstellt, ich erstell die immer zur Laufzeit...



Snoopy hat schon geschrieben, dass die Komponente durch ziehen auf das Formular automatisch erzeugt wird ...

Ich respektiere natürlich Deinen Umgang mit der Erzeugung und Freigabe von Komponenten in Delphi, allein Deine Meinung teile ich nicht mit Dir.

Gruß

Question_mark


----------



## Ralle (22 Juli 2009)

Wie gesagt, gerade die Threads in Delphi sind oft etwas eigen. Mal kann man sie nicht abschießen, mal beendet man sie, aber sie verschwinden einfach nicht komplett, sondern vegetieren als "Leiche" vor sich hin. Das ist etwas mystisch und erfordert einiges an Testerei. (Delphi7)


----------



## Human (22 Juli 2009)

> Ich respektiere natürlich Deinen Umgang mit der Erzeugung und Freigabe von Komponenten in Delphi, allein Deine Meinung teile ich nicht mit Dir.


 
Naja, ich programmiere so eigentlich auch nie, aber dass es nicht geht oder mit deinen Worten dass es dann im Gebälk mächtig splittert stimmt ja auch nicht ganz!



> Wie gesagt, gerade die Threads in Delphi sind oft etwas eigen. Mal kann man sie nicht abschießen, mal beendet man sie, aber sie verschwinden einfach nicht komplett, sondern vegetieren als "Leiche" vor sich hin. Das ist etwas mystisch und erfordert einiges an Testerei. (Delphi7)


 
Das ändert sich auch nicht mit den neueren Versionen...


----------



## Question_mark (22 Juli 2009)

*Programme können auch Zufallsgeneratoren sein *gg**

Hallo,



			
				Ralle schrieb:
			
		

> Das ist etwas mystisch und erfordert einiges an Testerei.



Das ist in keiner Weise mystisch oder rätselhaft, sondern erfolgt nach streng (vom OS ) vorgegebenen Regeln. Und die VCL von Delphi ist eben nicht threadsafe, d.h. wenn Du aus einem erzeugten Thread die Delphi VCL ansprichst und die Spielregeln über "Synchronize" nicht beachtest, knallt es eben. Das ist aber kein Fehler in Delphi, sondern vom Programmierer, und das Problem dürfte wohl in den meisten Hochsprachen bestehen.

Gruß

Question_mark


----------



## Human (22 Juli 2009)

Question_mark schrieb:


> Das ist in keiner Weise mystisch oder rätselhaft, sondern erfolgt nach streng (vom OS ) vorgegebenen Regeln. Und die VCL von Delphi ist eben nicht threadsafe, d.h. wenn Du aus einem erzeugten Thread die Delphi VCL ansprichst und die Spielregeln über "Synchronize" nicht beachtest, knallt es eben. Das ist aber kein Fehler in Delphi, sondern vom Programmierer, und das Problem dürfte wohl in den meisten Hochsprachen bestehen.


 
Damit hab ich eigentlich keine Probleme, alles was ein Thread wissen muss kriegt er direkt nach dem Erstellen von mir gesagt und wird dann erst gestartet oder eben wie erwähnt über Synchronize.

Das mysteriöse bei den Threads ist das Beenden (siehe http://www.sps-forum.de/showthread.php?t=29029 (der Teil mit Assigned(), den ich ausgeklammert habe), irgendwo schwirrt der noch rum, aber ist niemals vollkommen ganz weg. 
FreeOnTerminate hilft nicht, Free auch nicht...


----------



## Question_mark (22 Juli 2009)

*Hmm*

Hallo,

@human : hast du schonmal vor dem Terminate ein "Suspend" versucht ???

Gruß

Question_mark


----------



## Human (22 Juli 2009)

Das Suspend unterbricht nur die Ausführung der Threads temporär und wird nicht beendet:

Auszug aus der Delphihilfe:


> Mit Suspend können Sie die Ausführung eines Thread temporär unterbrechen. Mit Resume kann die Ausführung anschließend wieder aufgenommen werden. Suspend-Aufrufe können verschachtelt sein. Entsprechend oft muss dann aber auch Resume aufgerufen werden, bevor der Thread fortgeführt wird.


 
Und Terminate macht ja auch nix was wirklich intern verwendet wird, sondern nur als "Programmierhilfe" bereitgestellt wird um Threads, die ständig im Hintergrund laufen, zu beenden, wenn die Eigenschaft "Terminated" auf TRUE steht:



> procedure TThread.Terminate;
> begin
> FTerminated := True;
> end;


----------



## Question_mark (22 Juli 2009)

*...*



			
				human schrieb:
			
		

> Das Suspend unterbricht nur die Ausführung der Threads temporär und wird nicht beendet:



Es ist eigentlich völlig überflüssig, dass Du mir die Funktion "Suspend" erklären willst ... Es kann nur verhindern, dass Deine App vor dem Terminate versucht noch auf VCL Elemente zuzugreifen, der Thread ist dann eben eingeschlafen ...

Gruß

Question_mark


----------



## Question_mark (23 Juli 2009)

Hallo,



> Und Terminate macht ja auch nix was wirklich intern verwendet wird, sondern nur als "Programmierhilfe" bereitgestellt wird um Threads, die ständig im Hintergrund laufen, zu beenden, wenn die Eigenschaft "Terminated" auf TRUE steht:



Da hast Du allerdings übersehen, dass in den gängigen Hochsprachen jedes Property die Eigenschaft "read" und "write" hat und dementsprechend beeinflusst werden kann.

Gruß

Question_mark


----------



## Human (23 Juli 2009)

Question_mark schrieb:


> Hallo,
> 
> 
> 
> ...


 


> property Terminated: Boolean read FTerminated;


 
Aber irgendwie kommt mir das vor, als wenn wir gerade über Äpfel (Thread greift auf VCL-Komponenten zu) und Birnen (Thread ist nach beenden immernoch (zumindest teilweise) da und lässt sich nicht komplett entfernen) sprechen...


----------



## Ralle (23 Juli 2009)

Human schrieb:


> Aber irgendwie kommt mir das vor, als wenn wir gerade über Äpfel (Thread greift auf VCL-Komponenten zu) und Birnen (Thread ist nach beenden immernoch (zumindest teilweise) da und lässt sich nicht komplett entfernen) sprechen...



Ja, ich kenne dieses eigenartige Verhalten auch. Es hat mich enorm viel Arbeit gekostet, das irgendwie hinzubasteln. Threads, die ich nochmal brauche halte ich an und benutze sie später wieder, völlig weg bekommt man die einfach nicht.

@qm
Ja qm, wir sind ja nun auch nicht total dämlich, Synchonize kenn ich grad noch. Leider macht das oft, den Geschwindigkeitsvorteil eines eigenen Thread wieder zunichte, weil auf irgendwelche Dinge vom BS gewartet wird.

Und klar folgt das OS strengen Regeln, sonst ginge gar nichts mehr und das sofort. Das Hauptprolem ist oft, daß man X verschiedene Komponenten, von X unterschiedlichen Herstellern, alle mit unterschiedlicher Qualität, nutzt. Da funkt schnell mal etwas dazwischen, ohne das man das so einfach rausbekommt. Wird bei der Exception, wie oben beschrieben, auch ein ähnliches Problem sein.


----------



## afk (23 Juli 2009)

Als (Mit-)Verantwortlicher für diesen Thread muß ich mich wohl auch mal einmischen:

Ich glaube nicht, daß das Ausgangsproblem was mit Threads zu tun hat. Aus den Ausführungen über das Problem bin ich allerdings nicht wirklich schlau geworden, da wären ein paar Zeilen Quelltext oder zumindest Teile davon bestimmt nicht schädlich gewesen. QM hat zwar recht mit seinen Ausführungen, daß nur Komponenten, die zur Laufzeit aus dem Programmcode heraus erzeugt werden (mit NIL als AOwner), später per .Free (oder mit FreeAndNil) im Code wieder freigegeben werden dürfen, aber auch das ist ja laut Snoopy123123 nicht die Ursache. 

Ein grundsätzliches Problem der Komponente kann ich ausschließen, dafür ist die bei uns zu häufig im Einsatz. Ohne weitere Infos ist das hier also nur ein Stochern im Nebel.


Gruß Axel


----------



## afk (23 Juli 2009)

Ralle schrieb:


> Ja, ich kenne dieses eigenartige Verhalten auch. Es hat mich enorm viel Arbeit gekostet, das irgendwie hinzubasteln. Threads, die ich nochmal brauche halte ich an und benutze sie später wieder, völlig weg bekommt man die einfach nicht.


Ganz offen gestanden kann ich das Problem nicht nachvollziehen. Ich habe einige Systemdienste programmiert, die über Wochen und Monate laufen und dabei mehr oder weniger permanent neue Threads erzeugen (einige Threads pro Minute) und wieder beenden, und da bleibt nichts übrig, was nicht völlig weg zu bekommen ist.

Das Hauptproblem beim Verwenden von Threads liegt IMHO darin, daß ein Thread möglichst auf nichts von der VCL zugreifen sollte, was nicht komplett innerhalb des Threads erzeugt wurde. Und mit innerhalb des Threads meine ich ausschließlich in der Execute-Methode, da die Methoden Create und Co. noch innerhalb des Threads aufgerufen werden, in dem die TThread-Klasse instanziert wird.

Und zum Thema Suspend und Terminate:
Suspend legt den Thread schlafen, das ist richtig, aber terminiert wird ein Thread nur, wenn die Execute-Methode verlassen wird. Ein schlafender Thread wird also erst terminiert, nachdem er wieder aufgeweckt wurde. Und Terminate fordert zwar tatsächlich nur die Execute-Methode durch setzen der Terminated-Eigenschaft auf, sich zu beenden, aber für den Code in Execute ist man selbst verantwortlich, und muß dann die Eigenschaft Terminated entsprechend berücksichtigen. Wenn die Execute verlassen wird, wird der Thread dann auch ordnungsgemäß beendet, jedenfalls laut meinen Erfahrungen. Und bei gesetzten FreeOnTerminate wird auch der von TThread belegte Speicher ordentlich wieder freigeräumt.


Gruß Axel


----------



## Ralle (23 Juli 2009)

Zugriff auf Komponenten oder die Applikation an sich, nehme ich natürlich nur über Synchonize. Ich hatte schon Thread, die sich trotz aller Versuche geweigert haben das OnTerminate-Ereignis zu bringen. Nach meiner bisherigen Erfahrung passiert das tatsächlich nie mit kleinen Testanwendungen. Erst wenn es dann größer und verwickelter wird (Clientfenster, viele Komponenten etc.) passiert das dann irgendwann. Im Moment hab ich einen SQL-Server, der direkt in meine Anwendung integriert ist. Unter bestimmten, nachvollziehbaren Voraussetzungen löse ich da auch eine Exception aus, kann aber nicht herausfinden woran das genau liegt (keine Quellcode, lohnt nicht, den zu kaufen). Aber in einer kleinen Testanwendung passiert das nicht.  Da darf man sich dann einen Wolf suchen, wahrscheinlich hab ich denn auch doch zu wenig Ahnung von den wirklichen Internas von VCL, Delphi, Windows. Aber das will ich ja eigentlich auch gar nicht, dann wär ich C-Programmierer geworden.


----------



## Human (23 Juli 2009)

afk schrieb:


> Das Hauptproblem beim Verwenden von Threads liegt IMHO darin, daß ein Thread möglichst auf nichts von der VCL zugreifen sollte, was nicht komplett innerhalb des Threads erzeugt wurde. Und mit innerhalb des Threads meine ich ausschließlich in der Execute-Methode, da die Methoden Create und Co. noch innerhalb des Threads aufgerufen werden, in dem die TThread-Klasse instanziert wird.


*ACK*



afk schrieb:


> Und zum Thema Suspend und Terminate:
> Suspend legt den Thread schlafen, das ist richtig, aber terminiert wird ein Thread nur, wenn die Execute-Methode verlassen wird. Ein schlafender Thread wird also erst terminiert, nachdem er wieder aufgeweckt wurde. Und Terminate fordert zwar tatsächlich nur die Execute-Methode durch setzen der Terminated-Eigenschaft auf, sich zu beenden, aber für den Code in Execute ist man selbst verantwortlich, und muß dann die Eigenschaft Terminated entsprechend berücksichtigen.


 
immernoch *ACK*



afk schrieb:


> Wenn die Execute verlassen wird, wird der Thread dann auch ordnungsgemäß beendet, jedenfalls laut meinen Erfahrungen. Und bei gesetzten FreeOnTerminate wird auch der von TThread belegte Speicher ordentlich wieder freigeräumt.


 
Um mal auf wieder auf das andere Thema zu verweisen (http://www.sps-forum.de/showthread.php?p=207828#post207828), 2. Punkt, dass ich das "not Assigned(ReadThread)" habe, das musste ich machen weil der Thread, trotz FreeOnTerminate und FreeAndNil, immernoch irgendwo rumschwirrt, zwar nichts macht, aber irgendwas ist da noch, wie so ein böser Dämon!


----------



## afk (24 Juli 2009)

Human schrieb:


> Um mal auf wieder auf das andere Thema zu verweisen (http://www.sps-forum.de/showthread.php?p=207828#post207828), 2. Punkt, dass ich das "not Assigned(ReadThread)" habe, das musste ich machen weil der Thread, trotz FreeOnTerminate und FreeAndNil, immernoch irgendwo rumschwirrt, zwar nichts macht, aber irgendwas ist da noch, wie so ein böser Dämon!


Zu dem Punkt hab ich mittlerweile in dem entsprechenden Thread eine Antwort geliefert (siehe hier).


Gruß Axel


----------



## afk (24 Juli 2009)

Ralle schrieb:


> Nach meiner bisherigen Erfahrung passiert das tatsächlich nie mit kleinen Testanwendungen. Erst wenn es dann größer und verwickelter wird (Clientfenster, viele Komponenten etc.) passiert das dann irgendwann.


Mit der Größe der Anwendung hat das IMHO wenig zu tun (meine Systemdienste sind auch recht komplex), aber mit Sicherheit steigt mit der Anzahl der eingesetzten (Fremd-) Bibliotheken und Komponenten die Wahrscheinlichkeit des Auftretens von Fehlern. Nach meinen Erfahrungen übrigens bei gekauften Bibliotheken genau so häufig wie bei Freien (auch wenn QM oft einen anderen Standpunkt vertritt). Bei Fehlern, für die man auch noch bezahlt hat, tut man sich allerdings wesentlich leichter, dem Verantwortlichen die Pest an den Hals zu wünschen ... 


Gruß Axel


----------



## Ralle (24 Juli 2009)

@afk

Nicht zu vergessen, das auch die VLC diverse Fehler enthält!


----------



## alfonsmoeller (25 Juli 2009)

Hallo Snopy123123!
In VB beende ich die Verbindung wie folgt:

Private Sub Trennen()
' Verbindung abbauen
Dim RetCode As Long
If hConnection <> 0 Then
    RetCode = daveDisconnectPLC(hConnection)
    daveFree hConnection
    hConnection = 0
End If
If hInterface <> 0 Then
    RetCode = daveDisconnectAdapter(hInterface)
    daveFree hInterface
    hInterface = 0
End If
If hSocket <> 0 Then
    RetCode = closePort(hSocket)
    hSocket = 0
End If
End Sub

Das hat von Anfang an auf Anhieb funktioniert. Habe noch nie eine
Beschwerde von Windows (98,WIN2000,XP und Vista) gesehen.
m.f.G. alfonsmoeller


----------



## marcengbarth (27 Juli 2009)

Zeig doch mal etwas Quellcode, wenn dein Projekt nicht zu geheim ist. Ich verwende TNoDave relativ oft und hatte noch nie Probleme damit im OnClose der Anwendung die Verbindung zu trennen.

Evtl. ist dein Problem, dass der Thread noch läuft, du die Verbindung aber schon getrennt hast. 

Versuch's mal mit WaitFor beim Beenden des Threads.


----------



## Human (27 Juli 2009)

marcengbarth schrieb:


> Zeig doch mal etwas Quellcode, wenn dein Projekt nicht zu geheim ist. Ich verwende TNoDave relativ oft und hatte noch nie Probleme damit im OnClose der Anwendung die Verbindung zu trennen.
> 
> Evtl. ist dein Problem, dass der Thread noch läuft, du die Verbindung aber schon getrennt hast.
> 
> Versuch's mal mit WaitFor beim Beenden des Threads.


 
In der TNoDave wird der Thread beim schließen der Verbindung der Thread geschlossen und die Verbindung wird beim freigeben geschlossen... :TOOL:


----------



## Snoopy123123 (4 August 2009)

marcengbarth schrieb:


> Zeig doch mal etwas Quellcode, wenn dein Projekt nicht zu geheim ist. Ich verwende TNoDave relativ oft und hatte noch nie Probleme damit im OnClose der Anwendung die Verbindung zu trennen.
> 
> Evtl. ist dein Problem, dass der Thread noch läuft, du die Verbindung aber schon getrennt hast.
> 
> Versuch's mal mit WaitFor beim Beenden des Threads.





Von geheim hat da niemand was gesagt ! Hier mal ein paar Schnipsel, Die Fehlermeldung beim Schliessen bekomme ich übrigens immer noch. 



procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
vtest.Terminate;
vtest.WaitFor;
vtest.free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
vTest := tTest.Create(false);
end;


procedure TTest.execute;
var
MyNoDave : TNoDave;
begin

MyNoDave := TNoDave.Create(nil);
MyNoDave.IPAddress:= 'XXX.X.XX.XX';
MyNoDave.BufLen:= 100;
MyNoDave.CPUSlot:= 2;
MyNoDave.IntfName:= 'IF1';
MyNoDave.IntfTimeout:= 1500000;
MyNoDave.Protocol:= daveProtoISOTCP;
MyNoDave.Active:= True;

while not Terminated do begin
beendet := true;
i:=i+1;
Zaehl:= Zaehl+1;
Form1.Edit2.Text:= intToStr(Zaehl);

update(MyNoDave);
//self.free;
end; //while


mynodave.Active:= false;
MyNoDave.Free;

end;


----------



## Question_mark (4 August 2009)

*Ist Delphi LibNoDave Komponente threadsafe ???*

Hallo,

lese doch einfach nochmal den letzten Beitrag von delfiphan in diesem Fred durch ...

http://www.delphi-forum.de/printview.php?t=93880&start=0&sid=1128d3dcef33b2e9d9a022f8a62b4bb3

Das mit dem threadsafe kann afk bestimmt beantworten.

Gruß

Question_mark


----------



## Question_mark (4 August 2009)

*Ein Versuch, mehr nicht ..*

Hallo,

@snoopy123123

versuche mal folgendes :


```
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  [COLOR="Red"]vtest.FreeOnTerminate := FALSE;[/COLOR]
  vtest.Terminate;
  vtest.WaitFor;
  vtest.free;
end;
```

Delphi hat da manchmal noch einige kleine Probleme mit dem Beenden von Threads, da läuft manchmal nicht alles so rund wie gewünscht.

Gruß

Question_mark


----------



## Question_mark (4 August 2009)

*Delphi und Threads*

Hallo,

und hier noch ein kleines Tut von 'Luckie' aus einem Delphi-Forum. Ich denke mal, da wird einiges etwas klarer und verständlicher. Was Luckie in seinem Tut leider nicht berücksichtigt hat, sind diese kleinen Fehler in Delphi, u.a. beim WaitFor  

http://www.delphi-library.de/topic_ThreadProgrammierung+unter+Windows+mit+Delphi_16627.html&sid=67ecc9a2da1cae3ba5771939cc05e609

Gruß

Question_mark


----------



## Question_mark (4 August 2009)

*...*

Hallo,

und das hier :



> MyNoDave.Free;



gehört mit Sicherheit nicht in die Execute Methode des Threads rein, sondern eher in das CanClose des Hauptformulars. 

Gruß

Question_mark


----------



## Human (4 August 2009)

Question_mark schrieb:


> Hallo,
> 
> und das hier :
> 
> ...


 
So wie das oben gemacht ist schon, das wird ja auch in dem Thread erstellt!


----------



## Question_mark (4 August 2009)

*???*

Hallo,



			
				human schrieb:
			
		

> So wie das oben gemacht ist schon, das wird ja auch in dem Thread erstellt!



Sehe ich auch gerade, aber warum ist MyNoDave lokal deklariert ???
Das Dingsbumms lebt ja nur in der Execute Methode des Threads.

Gruß

Question_mark


----------



## Human (5 August 2009)

Was ich darin zu beanstanden hätte wäre diese Zeile:



> Form1.Edit2.Text:= intToStr(Zaehl);


 
Das sollte man eigentlich in ein Synchronize packen, kann ganz schön schiefgehen!!!


```
procedure TTest.UpdateEdit;
begin
  Form1.Edit2.Text:= intToStr(Zaehl);
end;
 
procedure TTest.execute;
begin
  ...
  ...
  Synchronize(UpdateEdit);
  ...
  ...
end;
```


----------



## Ralle (5 August 2009)

Human schrieb:


> Was ich darin zu beanstanden hätte wäre diese Zeile:
> 
> Form1.Edit2.Text:= intToStr(Zaehl);



Recht hast du, das geht garantiert schief (eigene Erfahrung), auch wenn man es nicht sofort sieht oder merkt. Synchronize ist ein absolutes Muß, wenn man auf die Oberfläche und damit ebend andere VCL-Komponenten zugreift. Eigentlich wäre das Alles so nicht unbedingt nötig, die Komponente startet intern ihren eigenen Thread, um Daten zu holen und liefert die dann mit dem OnRead-Ereignis.


----------



## marcengbarth (5 August 2009)

Versuch doch mal MyNoDave im FormCreate zu erzeugen, im Thread kannst du dann auch ohne synchronize() auf MyNoDave zugreifen, ohne das es kracht.

Den Thread würde ich auch nicht hier:


```
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  vtest.Terminate;
  vtest.WaitFor;
  vtest.free;
end;
```
sondern hier:


```
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  vtest.Terminate;
  vtest.WaitFor;
  vtest.free;
end;
```
oder hier:


```
procedure TForm1.FormDestroy(Sender: TObject);
begin
  vtest.Terminate;
  vtest.WaitFor;
  vtest.free;
end;
```

beenden.

Im CloseQuery kannst du z.B. eine Abfrage reinsetzen, ob die Anwendung wirklich geschlossen werden soll und dementsprechend CanClose true oder false setzen. Aber Objekte würde ich darin nicht freigeben.

Lade dir mal den FastMM4 runter und binde ihn ein, der Memorymanager zeigt dir beim Beenden an, wo es knallt. klick!


----------



## marcengbarth (5 August 2009)

Wie sieht denn eigentlich die Deklaration von TTest aus?

Wenn du das aus dem Delphi-Forum übernommen hast sieht es wahrscheinlich so aus:


```
TTest = class(TThread)
   private

   protected
   //procedure update;

   public
   procedure execute; override;
   procedure update(MyNoDaveUpdate : TNoDave);
   end;
```

Richtig sollte aber sein:


```
TTest = class(TThread)

   private

   protected
     procedure execute; override;
     procedure update(MyNoDaveUpdate : TNoDave);
   end;
```


----------



## afk (5 August 2009)

Question_mark schrieb:


> Das mit dem threadsafe kann afk bestimmt beantworten.


Yep, das kann ich. Ich nutze in meinen eigenen Programmen recht umfangreich Threads, und darum ist TNodave weitgehend auch threadsafe. Allerdings können logischerweise trotzdem Probleme auftreten (wie bei jeder anderen Komponente auch), wenn aus verschiedenen Threads überschneidend Properties verändert oder Methoden aufgerufen werden, die wiederum Properties verändern oder den internen Buffer nutzen. Und da die libnodave.dll aus prinzipiellen Gründen (liegt am S7-Protokoll) mit überschneidenden Funktionsaufrufen aus verschiedenen Threads heraus Probleme hat, habe ich das mit einer Critical Section innerhalb der Komponente abgesichert, was aber wiederum bei ungünstiger Programmierung vom Anwendungsprogramm zu einem Deadlock führen kann.

TNodave.Create und .Free innerhalb vom TThread.Execute sind kein Problem, allerdings stellt der Aufruf von Update(MyNodave) meine Kristallkugel mangels Quellcode vor ein kleineres Problem. Das größte Problem ist aber nach wie vor, daß eigentlich immer noch nicht klar ist, *WO* (im Programmcode) die Exception eigentlich ausgelöst wird. Die Debug-Units und/oder der Aufruf-Stack könnten hier durchaus  etwas mehr Klarheit bringen, alles andere hier ist und bleibt wilde Spekulation ...


Gruß Axel


----------



## Snoopy123123 (12 August 2009)

Hallo allerseits,

bin mittlerweile nochmal ein stückchen weitergekommen. Die Speicherlecks treten nur auf wenn ich mehrere Forms in der Anwendung habe.

Wenn ich nur meine Haupform benutze und die Komponente mit formcreate erstelle und dann über nen thread die Daten lese funktioniert und die Anwendung lässt sich auch sauber schliessen.
Füge ich nun eine zweite form ein, und dabei meine ich nur die blanke form dann tritt der speicherfehler beim schliessen auf. Kommentiere ich nun das 
Application.createform im Projectquelltext aus dann schliesst die Anwendung wieder sauber. Habt ihr ne erklärung hierfür ?


```

```
program Project1;

uses
  FastMM4,
  Forms,
  Unit1 in 'Unit1.pas' {Form1},

  Unit3 in 'Unit3.pas' {Setup};

{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  //Application.CreateForm(TSetup, Setup);
  Application.Run;
end.


----------



## Question_mark (12 August 2009)

*Ich weiss auch nicht mehr weiter ...*

Hallo,



			
				snoopy schrieb:
			
		

> Habt ihr ne erklärung hierfür ?



Ganz ehrlich gesagt, aus dem bisher geschriebenen kann ich keine Erklärung finden. Schick mir das Projekt doch mal über den Teich (mit evtl. Fremdkomponenten), dann kann ich am Wochenende mal nachschauen.

Gruß

Question_mark


----------



## afk (13 August 2009)

Snoopy123123 schrieb:


> Habt ihr ne erklärung hierfür ?


Verdammt, wo ist denn blos wieder meine Kristallkugel ... 

Mal im Ernst ...

FastMM liefert Logdateien mit Hinweisen darauf, *WANN* es im Programm kracht, 
im Debugger von der Delphi-IDE kann man bei einer Exception im Aufruf-Stack sehen, *WO* es im Programm kracht, 
wenn man ein Programm mit den Debug-DCUs erstellt, dann kann man das sogar dann noch schrittweise im Debugger laufen lassen, wenn das Programm in den Code der VCL abtaucht, um herauszufinden, *WARUM* es im Programm kracht,
...und wir sollen jetzt aufgrund des Hinweises auf eine auskommentierte Zeile im Projekt-Quelltext (also der allerobersten Ebene des Programms) sagen, woran das liegen kann ?

Oh, da ist ja meine Kristallkugel ... mal schauen ... ah, klar: 42 ! 


Gruß Axel


----------



## LowLevelMahn (13 August 2009)

*oder MadExcept*

http://www.madshi.net/madExceptDescription.htm

super Tool (sogar teilweise besser als EurekaLog) - wenn deine IDE läuft gibts sogar ein hinspringen zum Fehler auf Doppelklick

Freeware für nichtkommerziell


----------



## Snoopy123123 (13 August 2009)

Hallo allerseits,

ich habe den Fehler gefunden, Der Fehler war eigentlich total dämlich. Hätte ich auch schon viel früher drauf kommen können.

Beim erstellen der Komponente wird MyNoDave.BufLen:= 100; erstmal automatisch auf 100 eingestellt wenn es nicht explizit angegeben wurde.
Jetzt hatte ich in meinen Programm mit noDave Read 150 byte aus einem DB gelesen. Seltsamerweise hat das sogar funktioniert und erst beim schliessen der Anwendung zu dem Fehler geführt. 

Danke für eure Hilfe !


----------



## Snoopy123123 (13 August 2009)

afk schrieb:


> Verdammt, wo ist denn blos wieder meine Kristallkugel ...
> 
> Mal im Ernst ...
> 
> ...



42 war falsch !! 200 wäre richtig gewesen.
Hat die Glaskugel auch ein Bug ?

Ne mal ehrlich der Debugger hat mir hier nicht wirklich weiter geholfen. Ich habe so lange Code auskommentiert bis nur noch die NoDaveRead übriggeblieben ist. Dann hab ich irgendwann gemerkt das als ich mit der Länge rumgespielt habe und diese unter 100 war der Fehler nicht mehr auftrat. Ich will nicht sagen das man das das mit dem Debugger nicht richtig kann, gibt bestimmt möglichkeiten aber selbst fastMM hat mir alles mögliche an edit Feldern und Strings angezeigt obwohl ich genau wusste das der Fehler irgendwo von der NoDave Komponente kommt.

Danke für eure Unterstützung !


----------



## bike (13 August 2009)

Snoopy123123 schrieb:


> 42 war falsch !! 200 wäre richtig gewesen.
> Hat die Glaskugel auch ein Bug ?



Nein die Antwort ist 42.
Kann ich nur bestätigen 


bike


----------

