![]() |
SQL-Abfrage im Thread und füllen eines ListView
Hallo Leute,
ich schlage mich jetzt schon einen ganze Weile mit einem mit einem Problem rum, für das ich jetzt nur noch eine Lösung sehe: Threads. Hier mal zum Problem. Ich habe eine Art Terminplanungsprogramm in dem man Termine für bestimmte Ressourcen verwalten kann. Wenn ich dann einen Termin aufrufe, werden dort die Termindetails dargestellt und eine Historie für die ausgewählte Ressource angezeigt. Alles Funktioniert fehlerfrei, nur die Abfrage der Historie wird bei längerer Laufzeit des Programms ein Zeitfaktor. Der Grund dafür ist klar, denn wenn dann mit der Zeit so 40000 Termine eingetragen sind, und für die Historie eine SQL-Abfrage abgesetzt wird, benötigt der SQL-Server schon allein 5-7 Sekunden um die Daten bereit zu stellen. Leider wartet das Prog ja nach dem Query1.active:=True eben auf die Rückmeldung des Query's (ich verwende ZEOS und MySQL) bevor es dann mit dem Füllen des ListView weitergeht. Letzterer Schritt ist dann wieder uneingeschränkt schnell. Mein einziger erfolgversprechende Lösungsansatz wäre es, die SQL-Abfrage in einen Thread auszulagern, von diesem dann nach dem Anzeigen der Terminform unabhängig von Usereingaben das Listview füllen zu lassen. So fällt für den User die Wartezeit nicht mehr so deutlich auf, und im Listview könnte man solange ein "Daten werden abgerufen..." darstellen. So weit so gut. Aber wie fange ich das an. Leider hab ich von Threads recht wenig Ahnung und alle Tutorials und Bespiele beschränken sich leider auf recht simple Dinge wie eine String übergeben oder ein paar Werte zu berechnen. Meine erste Frage in diesem Zusammenhang, muß ich für einen Thread eine extra Unit verwenden, oder kann ich das in meiner Termin Unit mit unterbringen? Die zweite Frage wäre, kann ich aus einem Thread einfach per uses mein Datamodul einbinden und auf die Querys und die Connection zugreifen? Kann mein Thread dann einfach so auf das Listview zugreifen? Wie gesagt, ich hab von Thread wenig Ahnung, und ein Tutorial was mir diese Fragen beantwortet hab ich leider noch nicht gefunden. |
AW: SQL-Abfrage im Thread und füllen eines ListView
Zitat:
Zitat:
Zitat:
Sinnvoller ist hier die Daten en block/blockweise zurück an die Hauptapp zu geben und dann die Listview im Virtual Modus zu betreiben. |
AW: SQL-Abfrage im Thread und füllen eines ListView
Genau, hol doch nur die 10..100 neuesten History-Einträge pro Ressource und mach wenn der Benutzer weiter nach unten blättert ein Refresh auf alle. Oder einen Button "Alle Anzeigen"
|
AW: SQL-Abfrage im Thread und füllen eines ListView
Für eine genaue Antwort müsste ich ein wenig in meiner "Krabbelkiste" kramen, aber aus dem Kopf soviel:
Du erstellst deinen nebenläufigen Thread. Dieser *muss* eine eigene Verbindung aufbauen (Database, Transaction + Query!), er darf nicht die Verbindung des MainThread benutzen sonst knallt's. Den startest Du mit deiner Abfrage und lässt in nebenher dudeln. Wenn das Abfrageergebnis komplett ist, terminiert sich der Nebenthread idealerweise selbst. Um die Performance zu steigern, solltest du die ListView im VirtualMode (siehe OnData der ListView) einsetzen. Gruß Clemens |
AW: SQL-Abfrage im Thread und füllen eines ListView
Zitat:
Ich habe auch erst gedacht es länge an meiner Anwendung, aber als ich dann direkt mit dem MySQL-Adminstrator die gleichen Zeiten gemessen habe, denke ich mir das es wohl weniger an meiner Anwendung zu tun hat. So, ich werd das mal probieren mit ein thread. Aber meine erste Frage ist noch offen. Kann ich in der Terminunit einfach mit
Code:
den Thread mit einfügen, oder muß dafür eine eigene Unit existieren?
Type
MyThread = TThread end; wie ich die Daten an die Hauptapp zurückgeben weiß ich auch noch nicht, aber einen Schritt nach dem anderen. |
AW: SQL-Abfrage im Thread und füllen eines ListView
Zitat:
Zitat:
Mal ne andere Frage: Was genau dauert lange? Wenn du von den 40.000 Datensätzen einen auswählst, das abrufen der History oder das übertragen der Daten? Ich bin mir ziemlich sicher dass das schneller gehen muss. Vll. keine Indizies gesetzt? Falsche indizes? |
AW: SQL-Abfrage im Thread und füllen eines ListView
Tja, was das explizit so lange dauert kann ich dir nicht genau sagen.
Ich habe versucht das ganz mit Indizies versucht, aber ich habe dadurch keine nennenswerten Verbesserungen festgestellt. Ich mir sogar ein View erzeugt, welches nur die Felder enthält (sind glaub ich 6), aber auch wenn ich das abfrage, bekommen ich keine Geschwindigkeitssteigerung. Die Tabelle dir ich abfrage hat so 49 Felder, davon sind 2 Blob's der Rest String, Int und Datetime. Die beiden Blob's verwende ich einmal für die Ablage von Richtext und das andere für eine kleine Grafik 20x50 Pixel, welche aber nur bei den wenigsten DS tatsächlich gefüllt ist. In der View sind aber nur Datetime, String und int. Ich habe auch schon die Speichergrenzen in den Variablen des MySQL-Server angehoben, auch keine nennenswerten veränderungen. Wenn ich einen einzelnen DS über Lfdnr (primärindex) abfrage, geht das sehr schnell. Ich hab auch schon mal hier im Forum gefragt, wie MySQL den zu verwendeten Index auswähl. Da hieß es, wenn er existiert wird er automatisch verwendet. Ich weiß aber nicht, ob das stimmt. Beim Thread habe ich so meine Probleme. Da ich im Thread ein eigene Connection- und Query-Object verwenden soll, muß ich diese ja auch erst einmal erzeugen. Das kann aich aber nicht in der procedure Execute machen, sonder eher in einer Create. Gibt's die auch in einem Thread? Wenn ich in D7 über Datei-Neu-Weitere eine TThread-Unit anlege, dann gibt es dort keine Create-procedure. Und wenn ich eine anlege, dann meckert der Compiler. Grundsätzlich ist mir jede Lösung recht. Ohne TThread wär's an dieser Stelle einfacher. Andererseits würd ich gerne auch mal endlich diesen TThread-Kram verstehen. Steh da irgendwie auf einem Schlauch. :wall::wall: |
AW: SQL-Abfrage im Thread und füllen eines ListView
Jede (wirklich jede) Klasse hat eine Constructor und der heißt auch eigentlich Create.
Wenn der Compiler meckert, dann, weil die Klasse abgeleitet wurde (die ist immer abgeleitet, min. von TObject) und im Vorfahr etwas anders deklariert war, bzw. du das mit dem inherited oder inherited Create so nicht passt. Hilfreich dazu ist es sich die Vorfahr-Klasse mal anzuschauen, dann sieht man auch, wie der Constructor da aussieht ;) Ansonsten kann ich nur mal den Tip geben, im interface-Teil der neu zu erstellenden Klasse mal Strg-Leertaste zu drücken und dann wundern was da so auftaucht :mrgreen: |
AW: SQL-Abfrage im Thread und füllen eines ListView
Wieso musst Du eigentlich alle 40.000 Einträge anzeigen?
Wie ich das machen würde? Fetch-on-Demand. Ich lade mir 1000 oder so Einträge, und wenn jemand nach unten scrollt und den 1001sten sehen will, lade ich den nächsten Happen ein. Die Happen (1000 oder so) sind so gewählt, das das Laden sehr schnell geht. Die Query sieht immer gleich aus:
Code:
Und der Parameter :LastColumn enthält den Wert der Spalte 'SortColumn' des jeweils untersten Eintrags der breits geladenen Daten.
select first 1000 * from MyView where SortColumn>:LastColumn
Eigentlich keine große Sache. Kann aber sein, das dann die Query selbst lahm wird (wenn man die DB nicht richtig gepimpt hat). |
AW: SQL-Abfrage im Thread und füllen eines ListView
Wir haben das SQL Statement zwar nie gesehen bisher (das, und die Tabellendefinition wären nicht ganz unnützlich beim Analysieren hier ;) ), aber ich schmeisse zudem auch einfach mal in den Raum, dass Volltextsuchen der Art "LIKE '%substr%'" jeden Index aushebeln, und öfter mal Ursache für Performanceprobleme sind. Zeig doch mal das SELECT, sowie das aus der Tabelle erzeugte CREATE Statement her. 40k Sätze sind eigentlich nicht wirklich eine große Sache, ausser dein Server geht über eine eher mäßig schnelle Verbindung. Danach wurde übrigens auch schon gefragt: Ist der Server lokal, oder eine andere Maschine? Wenn letzteres: Wie ist er an deinen Client angebunden?
|
AW: SQL-Abfrage im Thread und füllen eines ListView
Liste der Anhänge anzeigen (Anzahl: 2)
Ok, hier mal ein Thread, der Datensätze an eine TListView schickt.
Der passt da noch nicht ganz für Dich (kein ZEOS, keine Query) aber das Prinzip bleibt gleich. Daten lesen und dann immer blockweise an die ListView schicken. so lange wie der Thread noch läuft per Queue und der letzte Abgleich erfolgt per Synchronize. (Damit wird sichergestellt, dass alle Einträge auch die ListView ausgeliefert werden)
Delphi-Quellcode:
Im Anhang ScreenShot, Exe-Datei und der gesamte Source
unit thread.SqlDataToListView;
interface uses Classes, ComCtrls, // TListView DB, DBClient, // TClientDataSet Generics.Collections; // TList<T> type TSqlDataToListViewThread = class( TThread ) private FListView : TListView; FData : TDataSet; protected procedure SendDataToListView( AListView : TListView; AItems : TList<TStrings>; Sync : Boolean = False ); protected procedure Execute; override; public constructor Create( AListView : TListView; const AFileName : string; CreateSuspended : Boolean = False ); destructor Destroy; override; end; implementation uses Windows, SysUtils; { TGetSqlDataToListViewThread } constructor TSqlDataToListViewThread.Create( AListView : TListView; const AFileName : string; CreateSuspended : Boolean ); begin inherited Create( CreateSuspended ); FListView := AListView; FData := TClientDataSet.Create( nil ); with FData as TClientDataSet do begin FileName := AFileName; end; end; destructor TSqlDataToListViewThread.Destroy; begin FData.Free; inherited; end; procedure TSqlDataToListViewThread.Execute; var lItems : TList<TStrings>; lItem : TStrings; lField : TField; begin // Datenverbindung öffnen try FData.Open; except on E : Exception do end; if FData.Active then // Wenn die Datenverbindung gesichert hergestellt ist dann können wir ja ans Werk try lItems := TList<TStrings>.Create; try while not Terminated and not FData.Eof do // Wir machen hier so lange, bis ... // ... der Thread abgebrochen wird // ... oder alle Datensätze gelesen wurden begin // Daten in einen Puffer schieben lItem := TStringList.Create; for lField in FData.Fields do begin lItem.Add( lField.AsString ); end; lItem.Add( DateTimeToStr( now ) ); // Daten in die Sammelliste schreiben lItems.Add( lItem ); // Nächster Datensatz FData.Next; // Wir tun mal so, als ob das hier gaaaanz lange dauert Sleep( Random( 15 ) ); if ( lItems.Count >= 10 ) or Terminated or FData.Eof then // Wenn der Block voll ist, // oder der Thread abgebrochen wurde // oder keine Daten mehr zu lesen sind // dann die Daten an das ListView ausliefern SendDataToListView( FListView, lItems, Terminated or FData.Eof ); end; finally lItems.Free; end; finally FData.Close; end; end; procedure TSqlDataToListViewThread.SendDataToListView( AListView : TListView; AItems : TList<TStrings>; Sync : Boolean ); var lItems : TObjectList<TStrings>; // Mal hier schnell geändert, sonst haben wir da ein Speicherleck :o) lItem : TStrings; begin if MainThreadID = GetCurrentThreadId then // Ei jo, wenn wir uns jetzt im MainThread-Kontext befinden, // dann können wir ja wieder ganz gemütlich auf das VCL-Gedöns zugreifen begin if Assigned( AItems ) then begin AListView.Items.BeginUpdate; try for lItem in AItems do begin with AListView.Items.Add do begin Caption := lItem[0]; lItem.Delete( 0 ); SubItems.Assign( lItem ); SubItems.Add( DateTimeToStr( now ) ); SubItems.Add( BoolToStr( Sync, True ) ); end; end; finally AListView.Items.EndUpdate; end; AItems.Free; // ** Hier ist das Free, und ... end; end else begin // Kopieren der übergebenen Daten-Liste lItems := TObjectList<TStrings>.Create; // ** ... hier das Create ... verkehrte Welt :o) for lItem in AItems do begin lItems.Add( lItem ); end; // übergebene Daten-Liste leeren (da schreibt der Thread ja wieder neue Daten rein) AItems.Clear; // Jetzt rufen wir uns selber nochmal auf, aber ... // 1. mit der kopierten Liste // 2. im MainThread-Kontext (Synchronized oder Gequeued) if Sync then Synchronize( procedure begin SendDataToListView( AListView, lItems, Sync ); end ) else Queue( procedure begin SendDataToListView( AListView, lItems, Sync ); end ); end; end; end. |
AW: SQL-Abfrage im Thread und füllen eines ListView
Hmm.. Bisserl kompliziert (zu viel Rumkopiererei), wenn man bedenkt, das man die Daten beim virtual Mode gar nicht in die ListView schreiben muss. Ich würde die Daten im Hintergrund einfach in eine TObjectList<TStringList> füllen und immer dann, wenn ein weiterer Block befüllt wurde, einfach per Synchronize die ListView.Items.Count neu setzen.
Aber als allgemeingültiges Proof-Of-Concept natürlich ok. |
AW: SQL-Abfrage im Thread und füllen eines ListView
Also als erstes heut morgen möchte ich gleich mal eine Kniefall für Sir Rufo :hello: machen. Das ich im Create gleich das Zeilobject mit übergeben kann, da wär ich im Leben nicht drauf gekommen. Wenn ich das so richtig verstanden habe, dann kann in der Create-Procedure dann ein Connection und Query object erzeugen. Das SQL-Statement könnte ich anstelle von afilename übergeben.
Und das Execute wird nur einmal ausgeführt. Damit werd ich das jetzt mal versuchen. Was ich bisher aus den verschieden Beispielen zusammengebastelt hatte hatte schon eine gewisse ähnlichkeit mit dem was du hier gepostet hast. Nur hab ich versucht, die Paramter für die Abfrage per Property zu übergeben, aber das hat noch nicht funktioniert. Wenn ich das gleich im Create machen kann spar ich mir noch code. Okay, ich frage mich grad noch, wann und wie sich der Thread dann zerstört? Und ich müßte die Objekte, die ich im Thread erzeuge ja auch noch freigeben. Dafür würde ich den destructor Destroy nehmen, wenn das geht. Zur Tabelle hier das das Create
Code:
Und hier mal mein SQL-Statement
CREATE TABLE `main` (
`Lfdnr` int(10) unsigned NOT NULL AUTO_INCREMENT, `Datum` datetime NOT NULL, `Zeit` varchar(45) DEFAULT NULL, `Da` varchar(45) DEFAULT '0', `Erl` varchar(45) DEFAULT '0', `Name` varchar(45) DEFAULT NULL, `Wer` varchar(45) DEFAULT NULL, `Termin` varchar(45) DEFAULT NULL, `Typ` varchar(45) DEFAULT NULL, `KZ` varchar(45) DEFAULT NULL, `Arbeiten` varchar(250) DEFAULT NULL, `Telefon` varchar(45) DEFAULT NULL, `Bemerkung` longtext, `Farbe` varchar(45) DEFAULT 'clScrollBar', `ZT` varchar(45) DEFAULT '0', `TB` varchar(45) DEFAULT '0', `TD` varchar(45) DEFAULT '0', `MA` varchar(45) DEFAULT NULL, `EW` varchar(45) DEFAULT '0', `Erinnerung` varchar(45) DEFAULT NULL, `FormatArbeiten` blob, `ID` varchar(45) DEFAULT NULL, `Mondruck` int(10) unsigned DEFAULT '0', `Auftrnr` varchar(10) DEFAULT NULL, `InArbeit` varchar(45) DEFAULT NULL, `rg` varchar(45) DEFAULT '0', `kmstand` int(10) unsigned DEFAULT '0', `recall` int(11) DEFAULT '-1', `lkukon` datetime DEFAULT NULL, `nachrep` longtext, `FD` varchar(45) DEFAULT '0', `TBKomm` longtext, `TDKomm` longtext, `FDKomm` longtext, `Gestrichen` varchar(45) DEFAULT '0', `HBKomm` longtext, `first` int(11) DEFAULT '0', `prior` int(11) DEFAULT '0', `next` int(11) DEFAULT '0', `erster` int(11) DEFAULT '0', `voheriger` int(11) DEFAULT '0', `naechster` int(11) DEFAULT '0', `weitergabe` int(11) DEFAULT '-1', `Firmenname` varchar(50) DEFAULT NULL, `Bild` blob, `debitor` varchar(45) DEFAULT NULL, `gruppe` int(11) DEFAULT '-1', `zegeplant` int(11) unsigned DEFAULT NULL, `frueher` int(11) DEFAULT '-1', `EWKomm` longtext, `TerminKomm` longtext, PRIMARY KEY (`Lfdnr`), KEY `Datum` (`Datum`,`Zeit`) ) ENGINE=InnoDB AUTO_INCREMENT=587 DEFAULT CHARSET=latin1;
Code:
Das Replace ist leider notwendig, damit alle Schreibweise auch erfasst werden.
Select Datum, Zeit, Wer, Arbeiten from main where REPLACE(KZ," ","")=:kennzeichen and lfdnr=erster
|
AW: SQL-Abfrage im Thread und füllen eines ListView
Zitat:
Wieso achtest Du beim *schreiben* der Daten nicht auf die Schreibweise? :gruebel: Dann brauchst Du das komische 'REPLACE' bei der Abfrage nämlich nicht mehr. Auch immer wieder gerne gefragt und durchaus interessant: Wer scrollt eigentlich durch die 40.000 Datensätze? |
AW: SQL-Abfrage im Thread und füllen eines ListView
Zitat:
Zitat:
Der Thread selber wird dann wie folgt gestartet: (siehe auch den restlichen Quelltest in der zip)
Delphi-Quellcode:
MyThread := TMyThread.Create( {[Parameter],} True {CreateSuspended} );
MyThread.OnTerminated := ThreadIstAmEnde; { Eine Methode die beim Beenden des Threads aufgerufen wird } MyThread.FreeOnTerminate := True; { Ist der Thread am Ende, dann soll er sich auch gleich vom Acker machen } MyThread.Start; { Jetzt geht es los } Zitat:
Zitat:
Code:
Ja und am besten für das Feld KZ einen Trigger (Insekt und Update) erstellen, der die Leerzeichen schon direkt beim Eintrag in die DB entfernt.
Select Datum, Zeit, Wer, Arbeiten from main where lfdnr=erster AND REPLACE(KZ," ","")=:kennzeichen
|
AW: SQL-Abfrage im Thread und füllen eines ListView
Zitat:
Kein Scrollt durch 40000 Datensätze. Darum ja auch die Abfrage. Bleiben ja nur so 20 übrig. |
AW: SQL-Abfrage im Thread und füllen eines ListView
@Sir Rufo: Ich hab jetzt mal versucht, den Code von dir zu übernehmen. Leider stoße ich da mal wieder an meine Grenzen. Das Projekt ist ein D7 geschrieben. Und teile deines Codes funktionieren unter D7 noch nicht.
Im Grund sollte das kein Problem sein, aber durch meine begrenzte Erfahrung mit Threads bedeuten die Änderungen für mich schon ein Problem. Zum einen sind da Sachen wie:
Delphi-Quellcode:
-> Kennt D7 ja nicht.
Generics.Collections
ebenso dieses:
Delphi-Quellcode:
und
TList<TStrings>.Create
Delphi-Quellcode:
(ich denke for .. in kennt D7 auch nicht).
for lField in FData.Fields do
Aber das krieg ich schon hin. Aber hiermit hab ich wirklich probleme:
Delphi-Quellcode:
geht wohl so in D7 auch noch nicht.
Synchronize( procedure begin SendDataToListView( AListView, lItems, Sync ); end )
Ich kann jetzt aber auch nicht mit dem Projekt auf D2010 umziehen. |
AW: SQL-Abfrage im Thread und füllen eines ListView
Das ist doch nur eine Inline Definition. Schreib die zu synchronisierende procedure einfach normal und ruf sie dort auf. Also aus:
Delphi-Quellcode:
wird dann
Synchronize( procedure begin SendDataToListView( AListView, lItems, Sync ); end )
Delphi-Quellcode:
Das ganze hier ist aber aus meiner Sicht komplett überflüssig, da das Problem in der Datenbankdefinition und der Abfrage liegt. Du treibst hier einen affenartigen Aufwand um Kosmetik zu betreiben.
procedure TMeinThread.SyncProc
begin SendDataToListView( AListView, lItems, Sync ); end; ... Synchronize(SyncProc) Dein KennZeichen Feld sollte normalisiert werden. Wo kommt der Abfrage Parameter her? Und wie sieht die Mastertabelle aus? |
AW: SQL-Abfrage im Thread und füllen eines ListView
Ich kann mich nur union anschließen.
Statt die Ursache in der Datenhaltung zu beseitigen, wird das "Problem" in einem Thread versteckt. Wieviel Nutzer verwenden diese Maske? Wie oft am Tag? Sicher, es sind nur ein paar Sekunden pro Aufruf. Aber ich vermute, dass Euer Hardwarehandler vielleicht bald mit einem großen Paket vorbeikommt, wenn Du den Stil beibehälst. |
AW: SQL-Abfrage im Thread und füllen eines ListView
Ok, unter D7 ist das so tatsächlich nicht möglich ;)
Mal sehen ob ich da eine D7-taugliche Version dir bereitstellen kann. Allerdings solltest du tatsächlich mal das Kennzeichen in den Index aufnehmen und mit einem Trigger sicherstellen, dass dort keine Leerzeichen auftauchen. Dann geht diese Abfrage bestimmt wie der Teufel
Code:
EDIT: Da fällt mir doch gerade auf, dass du das Feld erster auch in den Index aufnehmen solltest ;)
Select Datum, Zeit, Wer, Arbeiten from main where lfdnr = erster AND KZ = :kennzeichen
|
AW: SQL-Abfrage im Thread und füllen eines ListView
Zitat:
Investiere eine Stunde Arbeit und bring Deine DB auf Vordermann. Auch Benutzer sollten sich an ein wenig Datenerfassungsdiziplin gewöhnen können. oder willst Du auch noch alle "/" durch "7" ersetzen? Aber nur wenn die Daten am Freitag erfasst wurden..... Gruß K-H |
AW: SQL-Abfrage im Thread und füllen eines ListView
Ihr habt ja alle Recht. Und dank jfheins, der mich mit dem Befehl Explain auf die Richtige spur gebracht hat, hab ich das Problem mit der langen Abfrage mittlerweile auch lösen können.
Und...tatsächlich lag es an einem Index, den MySQL nicht verwendet hatte, weil ich dort ein Feld zuviel drin hatte. Ich wußte nur nicht, wie ich sehen kann, welchen Index MySQL denn bei einer Abfrage verwendet. Jetzt ist bezüglich der Abfrage alles wieder top. Liegt jetzt bei 30-40 Milisekunden. Aber die Thread-Problematik wollte ich trotzdem bis zum Ende durchziehen, denn es hilft mir vielleicht mal an andere Stelle, wenn ich jetzt das ganze hinbekomme und verstehe. Deswegen, würde ich gerne an dieser Stelle noch probieren, bis ich die Abfrage über den Thread hinbekommen habe. Auch wenn ich es später so nicht im Code verwenden werde (weil ja jetzt nicht mehr notwendig) |
AW: SQL-Abfrage im Thread und füllen eines ListView
Im Grunde ist das mit den Threads recht einfach, vor allem wenn man TThread als Basis nimmt. Kurzform: Alles was in der überschriebenen Methode "Execute()" passiert bzw. da heraus aufgerufen wird, passiert in einem eigenen Thread. Bamms. Abgesehen davon ist ein TThread-Nachfahre eine Klasse wie jede andere auch.
Was das ganze etwas verkompliziert, ist das Zusammenspiel mehrerer Threads, so z.B. mit dem Hauptthread deiner Anwendung, in dessen Kontext u.a. alles was mit der VCL GUI zu tun hat läuft. Da kommen dann so Spiele wie Synchronisation hinzu. Als einfachst-mögliche Fausregel könnte man eventuell sagen: Nutze in einem Thread niemals Dinge, die nicht innerhalb des Threads erstellt wurden. "Innerhalb des Threads" heisst bei TThread, dass es entweder in dessen Kontruktor, oder der Execute-Methode. Gemein ist dabei, dass es an sich prinzipiell geht, und 1000 Mal auch ohne Probleme, aber auch das wir einem eines schönen Tages in den Hintern beissen. Daher gleich rigoros sein, und nicht "rumhacken". Sobald man mit anderen Threads kommunizieren will (z.B. einem VCL Control eine StringList unterjubeln), muss man threadsichere bzw. threadsichernde Wege wählen, wozu das direkte Beschreiben von Properties (oder aufrufen von Methoden) nicht zählt, es sein denn, man tut dies in einer Critical-Section (TCriticalSection), die die beteiligten für die Dauer der Operation zusammenführt. Alternativ, und das ist mein Favorit, Windows-Messages vom Thread an ein Formular schicken, und dort dann mit einem Handler reagiern. Btw: Schön, dass wir dich doch noch zur "Wurzelbehandlung" an der DB bekommen haben - das beruhigt meinen Magen ;) |
AW: SQL-Abfrage im Thread und füllen eines ListView
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:37 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