Autor |
Beitrag |
Gunther Troost
Beiträge: 18
Windows 10, 64 bit
Delphi 5
|
Verfasst: So 08.12.19 14:26
Hallo Leute,
habe einen Effekt festgestellt (Delphi 5). Beim Schließen von Datenbanken (Database-Komponente) konnten aus irgendeinem unerklärlichen Grund die Tabellen nicht alle geschlossen werden. Dabei habe ich festgestellt, dass in der Unit DBTables die Prozedur CloseDatasets wie folgt programmiert wurde:
Delphi-Quelltext 1: 2: 3: 4:
| procedure TDatabase.CloseDataSets; begin while DataSetCount <> 0 do TDBDataSet(DataSets[DataSetCount-1]).Disconnect; end; |
Bei meinem Programm war beim Schießen der Effekt aufgetreten, dass die Property Datasetcount nicht 0 wurde. Es gab damit eine Endlosschlleife. Ich weiß leider nicht, welche Tabelle das Problem erzeugt, weil der Name des letzten Datasets nur als Leerzeichen ausgegeben wird.
Ich habe - und bitte jetzt keine Kommentare, dass man das nicht machen soll - die Routine wie folgt geändert.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure TDatabase.CloseDataSets; var i,n: integer; loDS: TDBDataSet; begin n := DataSetCount; for i := n-1 downto 0 do begin loDS := TDBDataSet(DataSets[i]); if loDS <> nil then loDS.Disconnect; end; end; |
Nun gibt es wenigstens keine Endlosschleife mehr. Aber so richtig glücklich bin ich nicht damit.
Anmerkung, ich habe bei dem Formular in dem Close-Ablauf vor der Schließung der Database sämtliche onClick, OnChange und OnDrawColumnCell auf NIL gesetzt, trotzdem trat bei der originären DBTables-Version der Effekt auf. Daran kann es meines Erachtens auch nicht liegen. Irgendeine Routine hält eine Tabelle offen, weiß Zeus, welche.
Vielleicht habt Ihr eine Idee. Oder - was ich vermute, dass die Property DatasetCount nicht richtig gesetzt wird. Es gibt in der Database bei der Property keine Setprozedur, nur eine Leseprozedur GetDataSetCount. Die wird aus der Datasetliste belegt. Diese Liste scheint nicht richtig geleert zu werden. Aber es ist echt grausam, in Betriebssystemroutinen zu debuggen, weil das von Höcksken auf Stöcksken geht. Und außerdem habe ich nicht so viel Ahnung von den zugrundeliegenden Strukturen. Ich finde es nur merkwürdig, dass eine solche Routine so programmiert wurde, dass möglicherweise eine Endlosschleife entsteht.
Liebe Grüße
Gunther Troost
|
|
jasocul
Beiträge: 6388
Erhaltene Danke: 146
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Mo 09.12.19 08:26
Delphi 5 ist ja schon etwas älter und du benutzt offensichtlich noch die BDE.
Die Sourcen für den BDE-Zugriff haben sich aber scheinbar nicht mehr geändert.
Um der Ursache auf den Grund zu gehen, solltest du die folgende Methoden aus der Unit "Data.DB" (heißt in D5 evtl. anders) debuggen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| procedure TCustomConnection.RegisterClient(Client: TObject; Event: TConnectChangeEvent = nil); begin FClients.Add(Client); FConnectEvents.Add(TMethod(Event).Code); if Client is TDataSet then FDataSets.Add(TDataSet(Client)); end;
procedure TCustomConnection.UnRegisterClient(Client: TObject); var Index: Integer; begin if Client is TDataSet then FDataSets.Remove(TDataSet(Client)); Index := FClients.IndexOf(Client); if Index <> -1 then begin FClients.Delete(Index); FConnectEvents.Delete(Index); end; end; |
Ich vermute, dass du darüber rausbekommen kannst, welches deiner DataSets Probleme macht. Register Client füllt die Liste der DataSets, die über die Connection laufen und UnregisterClient leert diese Liste wieder, wenn alles richtig läuft.
Das heißt, dass darüber auch das Count gesteuert wird, das die Endlosschleife provoziert. Zumindest ist das mein Verdacht.
Sobald du weißt, welches DataSet die Ursache ist, kannst du ins Detail gehen und in deinem Source nachsehen, woran das eventuell liegen kann.
Für diesen Beitrag haben gedankt: Gunther Troost
|
|
Gunther Troost
Beiträge: 18
Windows 10, 64 bit
Delphi 5
|
Verfasst: Mo 09.12.19 10:24
Lieber Jasocul, danke für den Hinweis. Ich habe festgestellt, dass nicht irgendein Dataset dafür verantwortlich war, sondern bloß die Schleife nicht bis zum Ende durchlief. Allerdings habe ich feststellen müssen, dass die UnregisterClient-Prozedur selbst bei einem simplen "next" aufgerufen wird. Warum das? Keine Ahnung, aber das erscheimnt mir echt krass. Selbst wenn die Prozedur keine Prozessorzeit beansprucht, so ist das ständige Registrieren und Unregistrieren doch komisch. Bei einer ganz normalen Datensatznavigation, wie gesagt. Werden die Datasets beim Schließen automatisch unregistriert? Dann ist das verständlich, jedoch kaum bei einer Datensatznavigation. Das muss ich mir mal genauer ansehen. Allerdings benötige ich häufig eine Aktualisierung einzelner Datasets durch Löschen und Setzen von "Active". Denn so umgehe ich die Fehler beim Eintragen neuer Datensätze: "Datensatz vom anderen Nutzer geändert, Datensatz konnte nicht eingetragen werden..."
|
|
jasocul
Beiträge: 6388
Erhaltene Danke: 146
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Mo 09.12.19 11:37
Gunther Troost hat folgendes geschrieben : | Ich habe festgestellt, dass nicht irgendein Dataset dafür verantwortlich war, sondern bloß die Schleife nicht bis zum Ende durchlief. |
Naja, die Schleife wird nur dann nicht abgeschlossen, wenn die DataSet-Liste nicht aufgelöst werden kann. Das passiert aber beim UnRegister. Dort werden die Einträge aus der DataSet-Liste entfernt (FDataSets.Remove(TDataSet(Client)).
Daher war mein Vorschlag zu prüfen, bei welchem DataSet das fehlschlägt.
|
|
Gunther Troost
Beiträge: 18
Windows 10, 64 bit
Delphi 5
|
Verfasst: Mo 09.12.19 15:32
Danke nochmals,
doch ich bin da leider nicht wirklich weiter gekommen. Eines weiß ich nun, dass beim Beenden eine dermaßen heftige Aktivität (Closeactions, Notifications der einzelnen Felder ...bläuft, dass man bei der Fehlersuche sc hier verrückt wird. Ich habe die Close-Prozedur extrem verschlankt, gewisse Vorgaben, die ich gemacht habe, und Fehlerspeicherungen in Textdateien habe ich rausgeschmissen, weil die korrket nur bei einem laufenden Programm funktionieren (so sieht es wenigstens aus) und Fehler machen, wenn dieses gerade heruntergefahren wird.
Ich dachte immer, wenn man statt mit Application.Terminate, mit Halt das Programm beendet, wäre das ein brutaler Abbruch, Pustekuchen, da laufen die gleichen Routinen ab.
Was ich zudem festgestellt habe, ist, dass das Beenden nicht immer gleich abläuft. Gestern habe ich problemlos das Programm beenden können, heute morgen funktionierte es wieder nicht. Dabei habe ich an der Prozedur Formclose nichts geändert. Der Fehler ist also sicher woanders zu suchen. Jetzt habe ich in die Formclose-Prozedur explizit die Destroy-Befehler der drei Datenbanken eingebaut und es funktioniert nun wieder. Mal sehen, wie lange!
|
|
jasocul
Beiträge: 6388
Erhaltene Danke: 146
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Di 10.12.19 07:28
Gunther Troost hat folgendes geschrieben : | Was ich zudem festgestellt habe, ist, dass das Beenden nicht immer gleich abläuft. Gestern habe ich problemlos das Programm beenden können, heute morgen funktionierte es wieder nicht. Dabei habe ich an der Prozedur Formclose nichts geändert. Der Fehler ist also sicher woanders zu suchen. |
Davon bin ich ausgegangen. Aber du musst erstmal feststellen, welches DataSet den Fehler verursacht. Im zweiten Schritt kannst du dann prüfen, wodurch das DataSet Probleme macht.
Gunther Troost hat folgendes geschrieben : | Jetzt habe ich in die Formclose-Prozedur explizit die Destroy-Befehler der drei Datenbanken eingebaut und es funktioniert nun wieder. Mal sehen, wie lange! |
Destroy? Du musst die armen Datenbank-Verbindungen doch nicht gleich umbringen
Versuche es doch erstmal mit einem Free. Allerdings vermute ich, dass du dann den Fehler wieder bekommst. Dennoch ist Destroy der falsche Ansatz.
Als Zwischenlösung kann man vielleicht so vorgehen. Aber gerade die BDE kann relativ empfindlich auf so harte Programmierung reagieren. Es wäre daher besser, die Ursache zu finden und zu beheben.
Ich stochere jetzt mal ein bisschen im Nebel:
Ich erinnere mich gerade, dass du etwas davon schriebst, dass du das Active aus- und einschaltest, um die Datensätze zu aktualisieren. Nutzt du dabei vielleicht auch Bookmarks? Falls die nicht freigegeben werden, können die vielleicht Probleme bereiten.
Wenn die Anwendung mal funktioniert und ein anderes mal nicht, könnte man die Tests ja so aufbauen, dass du das Programm startest, eine Sache damit machst und dann wieder beendest. Wenn es dann wieder daneben geht, hast du die Problemstelle schon etwas weiter eingekreist.
Ein weiter Ansatz wäre vielleicht, die DataSets zu schließen, bevor du das Programm beendest. Entweder ist damit dein Problem behoben oder du findest so evtl. das DataSet, das nicht so will, wie du erwartest.
|
|
Narses
Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Di 10.12.19 11:04
Moin!
Ohne im Detail alles verfolgt und verstanden zu haben: mal geht´s, mal nicht? Das hört sich nach einem Kandidaten für use-after-free an... (mal sind die (bereits freigegebenen) Objekte noch da, mal nicht -> crash) Wäre zumindest einen Gedanken wert.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
Gunther Troost
Beiträge: 18
Windows 10, 64 bit
Delphi 5
|
Verfasst: Fr 03.01.20 07:20
Entschuldigt, dass ich so spät reagiere, aber es hat bisher so, wie ich es gemacht habe, funktioniert, ohne diesen komischen Fehler.
Und nein, ich benutze keine Bookmarks, und nein, ich benutze die Objekte auch nicht mehr, nachdem ich sie freigegeben habe. Das ist alles irgendwie eine Frage der DB-Routinen von Delphi. Doch da begibt man sich schnell in die tiefsten Tiefen der OO-Programmierung und beißt sich schnell fest. Da das Beenden des Programms jetzt soweit stabil ist, habe ich aus Performancegründen ein anderes Problem zu bearbeiten, aber das ist hier nicht Thema.
Danke für Eure Hilfestellungen, wünche Euch allen ein gutes Neues Jahr
Gunther
|
|
|