|
![]() |
|
Registriert seit: 23. Jan 2008 3.687 Beiträge Delphi 2007 Enterprise |
#1
Aloah!
So ganz so grün bin ich in Sachen Multithreading ja eigentlich nicht - dachte ich - aber in meinem aktuellen Projekt hüpft mir gelegentlich dann doch die gelegentliche AV ins Gesicht. Der Sinn des Teils ist: Es gibt eine Liste von Anfragen, die via TCP/IP an ein anderes System gesendet werden. Da die Antworten dieses Systems keine Zuordnung zur gemachten Anfrage zulassen, muss auf die Antwort gewartet werden, bevor eine nächste geschickt werden kann. Die Anfragen werden in einem definierten Zyklus verschickt, so dass ich das in einen Thread ausgelagert habe, der immer wieder diese Anfragen abschickt wenn sie anstehen, und zurück gelieferte Antworten verarbeitet (=Daten in meine DB schreibt). Ich versuche mal die grobe Struktur darzustellen:
Delphi-Quellcode:
Was mich fuchst ist, dass das Erzeugen des DBEntryThreads ab und an knallt (so im Schnitt alle 20 Mal ein Mal, die Zykluszeit ist bei 2 Sekunden), obwohl der Konstruktor selbst keine AV erzeugt (getestet via try..except drum rum und bei Exception Logfile machen, was nie geschah). Das try..Except um den Aufruf des Konstruktors dagegen läuft wie gesagt ab und an auf den Hammer, ich komme beim Debuggen nur nicht an die genaue fehlerhafte Zeile, da diese sich nicht explizit in meinem Code zu befinden scheint.
unit MyThreads;
interface type TFetchThread = class(TThread) private FetchGroups: TFetchGroupList; // Eine List mit Instanzen von TFetchGroup, die sind nichts großartig spannendes. Reine Datenhalter. Sock: TClientSocket; Con: TUniConnection; Qry: TUniQuery; CycleThread: TCycleThread; NewDataArrived: Boolean; WaitingForReply: Boolean; SockForm: TForm; procedure IssueFetch(fetchGroupIndex: Integer); procedure HandleFetchReply(aReplyBuffer: TSockBuffer); procedure MakeDBEntriesForGroup(groupID: Integer; buf: TFetchEntryBuffer); procedure InitIssueFetch; protected procedure Execute; override; public constructor Create(aSocket: TClientSocket; aSocketForm: TForm; aDBConnection: TUniConnection); destructor Destroy; override; procedure SocketDataReady(aBuffer: TSockBuffer); end; implementation constructor TFetchThread.Create(aSocket: TClientSocket; aSocketForm: TForm; aDBConnection: TUniConnection); var i, m: Integer; begin inherited Create(true); Sock := aSocket; // Socket kommt vom MainForm SockForm := aSocketForm; // Das Handle brauche ich später auch // Eigene Connection für den Thread erstellen, Daten von der übergebenen Connection nehmen try Con := TUniConnection.Create(nil); Con.ProviderName := aDBConnection.ProviderName; Con.Server := aDBConnection.Server; Con.Database := aDBConnection.Database; Con.Port := aDBConnection.Port; Con.Username := aDBConnection.Username; Con.Password := aDBConnection.Password; Con.LoginPrompt := false; Con.Connect; except Con.Free; raise Exception.Create('Mäh'); end; // Thread-eigene Query try Qry := TUniQuery.Create(nil); Qry.Connection := Con; except Qry.Free; raise Exception.Create('Muh'); end; // Gruppen füllen, dies ist die einzige Stelle, an der an diesen strukturell etwas gemacht wird FetchGroups := TFetchFunctions.MakeFetchGroups(Qry); CycleThread := TCycleThread.Create; CycleThread.Items := FetchGroups; CycleThread.Resume; self.Resume; end; // WaitingForReply heisst, es wurde eine Anfrage gesendet, die Antwort steht noch aus. In der Zeit darf nichts gemacht werden. // NewDataArrived wird im SocketRead gesetzt, wenn die erwartete Menge Bytes angekommen und valide ist. procedure TFetchThread.Execute; var i, k: Integer; lowCycle: Integer; begin repeat if not WaitingForReply then begin // Gruppe suchen, die aktualisiert werden muss (die, die am längsten überfällig ist) lowCycle := 0; k := -1; for i := 0 to FetchGroups.Count-1 do begin if FetchGroups[i].CurrentCycleTime < lowCycle then begin lowCycle := FetchGroups[i].CurrentCycleTime; k := i; end; end; // Wurde eine gefunden, dann via Socket-Kompo auf dem MainForm die Anfrage senden if (k >= 0) then begin IssueFetchID := k; Synchronize(InitIssueFetch); end; end else begin // Wird eine Antwort zu einer Anfrage erwartet, und es ist eine eingetroffen, diese nun verarbeiten. if NewDataArrived then HandleFetchReply(ReplyBuffer); // Der Buffer ist ein array[0..8191] of Byte, mehr kommt definitiv nicht end; Sleep(1); until Terminated; end; procedure TFetchThread.HandleFetchReply(aReplyBuffer: TSockBuffer); var h: TFetchAnswerHeader; // ein record isValid: Boolean; buf: TFetchEntryBuffer; // array of Byte begin Move(aReplyBuffer[0], h, SizeOf(TFetchAnswerHeader)); // Header auf Validität prüfen isValid := DiverseDinge; if isValid then begin // ReplyGroupID wird in InitIssueFetch() gesetzt, und ist der Index der zuletzt angefragen Fetchgruppe in der Liste dieser SetLength(buf, FetchGroups[ReplyGroupID].ByteCount); Move(aReplyBuffer[SizeOf(TFetchAnswerHeader)], buf[0], FetchGroups[ReplyGroupID].ByteCount); MakeDBEntriesForGroup(ReplyGroupID, buf); end; NewDataArrived := false; WaitingForReply := false; end; // Mein Sorgenkind! Das erstellen des TDBEntryThreads knallt sporadisch, und zwar beim Erzeugen selbt. // Der Konstruktur läuft sauber durch, das hab ich getestet, dennoch gibt's ab und an eine AV an unterschiedlichen // Adressen. Mal 0, mal $FFFFFFFF, mal irgendwas im Codesegment, und dort immer leicht verschiedene. // Das try..except hier ist nur ein Workaround, den ich gern los wäre. Zudem greift dies nicht immer, selten springt // Delphi auch gleich ins CPU-Fenster, obwohl "bei Delphi-Exceptions stoppen" aus ist. Igitt! procedure TFetchThread.MakeDBEntriesForGroup(groupID: Integer; buf: TFetchEntryBuffer); var group: TFetchGroup; threadOkay: Boolean; begin group := FetchGroups[groupID]; threadOkay := false; repeat try TDBEntryThread.Create(Qry.Connection, group, buf, SockForm.Handle); threadOkay := true; except end; Sleep(1); until threadOkay; end; // Das ist besagter Konstruktor. Ein paar private Felder werden gesetzt, viel mehr nicht. constructor TDBEntryThread.Create(aCon: TUniConnection; aGroup: TFetchGroup; aBuf: TFetchEntryBuffer; aWnd: HWND); begin inherited Create(true); Con := aCon; Sql := TUniSQL.Create(nil); Sql.Connection := Con; Group := aGroup; Buf := aBuf; Wnd := aWnd; FreeOnTerminate := true; Resume; end; // Und hier der zugehörige Workload procedure TDBEntryThread.Execute; begin // Hier wird anhand von Infos aus der "Group" der Empfagspuffer interpretiert. Group wird dabei nur lesend angefasst. // Da das recht viel ist, durch diesen Kommentar ersetzt. Im wesentlichen wird ein SQL Statement zusammengestückelt. while Sql.Connection.InTransaction do Sleep(1); Sql.Execute; // Puffer zur Änderungserkennung für diesen Fetch-Aufruf speichern (einziger schreibender Zugriff auf Group) group.Buffer := Buf; group.FirstRun := false; end; // Wird vom MainForm aufgerufen, wenn OnSocketRead die geforderte Datenmenge gelesen hat procedure TFetchThread.SocketDataReady(aBuffer: TSockBuffer); begin ReplyBuffer := aBuffer; NewDataArrived := true; end; // Das hier macht der ominöse Cyclethread: Er zählt in den Fetchgruppen einen Zeitwert runter, // anhand dessen ermittelt wird welche Anfrage als nächste ansteht. procedure TCycleThread.Execute; var i: Integer; tickDelta: Int64; begin repeat tickDelta := GetTickCount-LastTickCount; LastTickCount := GetTickCount; for i := 0 to Items.Count-1 do Items[i].CurrentCycleTime := Items[i].CurrentCycleTime - tickDelta; Sleep(1); until Terminated; end; Ich hab mir ein wenig Sorgen um diese Groups gemacht, da diese ja ein Feld des FetchThreads sind, und sowohl vom Cyclethread als auch vom DBEntryThread dort hineingegriffen wird. Jedoch werden in beiden nur elementare Operationen ausgeführt, und die Struktur der Liste bleibt nach dem Konstruktor von TFetchThread für den Rest des Ablaufs immer gleich. Was hab ich hier nicht bedacht? Wäre prima, wenn trotz der Länge des Teils jemandem was auffällt. Danke schon mal! \\Edit: Hier mal ein Auszug aus meinem Fehlerlog (das schreibe ich im except-Teil der Methode MakeDBEntriesForGroup(), das ist hier der Länge wegen nicht im Code):
Code:
25:07:2011 12:46:17:625 : Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000 -> TDBEntryThread.Create(Qry.Connection, group, buf);
25:07:2011 12:46:31:859 : Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:47:00:953 : Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:47:04:562 : Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:47:21:609 : Zugriffsverletzung bei Adresse 00004244. Lesen von Adresse 00004244 -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:48:00:421 : Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:48:02:859 : Zugriffsverletzung bei Adresse 00004244. Lesen von Adresse 00004244 -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:49:27:796 : Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000 -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:49:45:890 : Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000 -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:49:49:937 : Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000 -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:49:53:203 : Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:49:53:984 : Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:50:00:500 : Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:50:06:125 : Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000 -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:50:07:796 : Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:50:08:140 : Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000 -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:50:12:203 : Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000 -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:50:44:234 : Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:50:52:703 : Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:51:52:156 : Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000 -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:52:03:109 : Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000 -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:54:52:859 : Zugriffsverletzung bei Adresse 00004244. Lesen von Adresse 00004244 -> TDBEntryThread.Create(Qry.Connection, group, buf); 25:07:2011 12:58:24:640 : Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF -> TDBEntryThread.Create(Qry.Connection, group, buf);
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
Geändert von Medium (25. Jul 2011 um 13:01 Uhr) |
![]() |
(Moderator)
Registriert seit: 23. Sep 2003 Ort: Bockwen 12.235 Beiträge Delphi 2006 Professional |
#2
Das ist aber nicht die vollständige Unit oder? Ich vermisse da die Declaration vom TDBEntryThread
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's |
![]() |
Registriert seit: 23. Jan 2008 3.687 Beiträge Delphi 2007 Enterprise |
#3
Nene, die ganze Unit hat 520 Zeilen und das eine oder andere ist noch in zwei weiteren. Hier passiert aber das Wesentliche. Falls die Deklaration aber hilfreich ist:
Delphi-Quellcode:
Im Destruktor wird nur Sql.Free; aufgerufen.
TDBEntryThread = class(TThread)
private Sql: TUniSQL; Con: TUniConnection; Group: TFetchGroup; Buf: TFetchEntryBuffer; Wnd: HWND; procedure ConfirmDataSent(valueCount: Integer); protected procedure Execute; override; public constructor Create(aCon: TUniConnection; aGroup: TFetchGroup; aBuf: TFetchEntryBuffer; aWnd: HWND); destructor Destroy; override; end; Ich hab den sporadischen Fehler über Mittag wieder bekommen. Also der, der nicht im Log landet, sondern den Debugger ins CPU-Fenster schickt:
Code:
Die Codestelle mit vorhergehender Zeile ist:
---------------------------
Benachrichtigung über Debugger-Problem --------------------------- In Projekt E:\Projekte\Server Template\Server\Server.exe trat ein Problem mit folgender Meldung auf: 'Anwendungsdefinierte Excpetion (Code 0xc0000028) bei 0x7c95eb93'. Prozess angehalten. Mit Einzelne Anweisung oder Start fortsetzen. --------------------------- OK --------------------------- 7C95EB8E call ntdll.RtlRaiseException 7C95EB93 jmp -$0001703f So ganz habe ich leider nicht nachvollziehen können wo genau das ist, so firm bin ich mit Assembler dann leider doch nicht ![]() PS: "Excpetion" ist aber auch nicht ganz richtig da im Fehlertext, hm? ![]() Edit: Laut Google ist 0xc0000028 STATUS_BAD_STACK. "An invalid or unaligned stack was encountered during an unwind operation." Was lese ich daraus? ![]() Edit2: Das MSDN ist da auch leider eher wenig hilfreich. ![]() User Action:
This is a Windows 2000 Executive STATUS error message. Choose an option from the message box. Then contact your technical support group because the application is broken.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
Geändert von Medium (25. Jul 2011 um 14:29 Uhr) |
![]() |
Registriert seit: 29. Mai 2002 37.621 Beiträge Delphi 2006 Professional |
#4
Das klingt, als ob du dir deinen Stack zerschossen hättest.
Michael
Ein Teil meines Codes würde euch verunsichern. |
![]() |
Registriert seit: 23. Jan 2008 3.687 Beiträge Delphi 2007 Enterprise |
#5
Ja, aber wie? Ich fummel nirgends mutwillig rum, kein Pointergeschubse, kein Handmade-Assembler, alles schönstes Object-Pascal
![]() Edit: Jetzt hab ich an der Stelle auch noch einen Stack-Overflow gesehen. Also irgendwas ist doch da ganz fies im Argen. AVs an Adressen wie 0 und FFFFFFFF sowie anderen, misaligned Stacks, Overflows... dabei wird dort doch nur die Täglich-Brot-Arbeit verrichtet, einen Thread loszutreten. Ich werd langsam blöd =) Edit: So, mal haarklein ge-try-excepted:
Delphi-Quellcode:
Das Fehlerlog dazu:
procedure TFetchThread.MakeDBEntriesForGroup(groupID: Integer; buf: TFetchEntryBuffer);
var group: TFetchGroup; threadOkay: Boolean; begin group := FetchGroupsInSQLOrder[groupID]; threadOkay := false; repeat try TDBEntryThread.Create(Qry.Connection, group, buf, SockForm.Handle); threadOkay := true; except on e: Exception do Log(FormatDateTime('dd.mm.yyyy hh:mm:ss.zzz', now)+' : '+e.Message+' -> TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)='+IntToStr(Length(buf))); end; Sleep(1); until threadOkay; end; constructor TDBEntryThread.Create(aCon: TUniConnection; aGroup: TFetchGroup; aBuf: TFetchEntryBuffer; aWnd: HWND); begin try inherited Create(true); except on e: Exception do Log(FormatDateTime('dd.mm.yyyy hh:mm:ss.zzz', now)+' : '+e.Message+' -> inherited Create(true);'); end; try Con := aCon; except on e: Exception do Log(FormatDateTime('dd.mm.yyyy hh:mm:ss.zzz', now)+' : '+e.Message+' -> Con := aCon;'); end; try Sql := TUniSQL.Create(nil); except on e: Exception do Log(FormatDateTime('dd.mm.yyyy hh:mm:ss.zzz', now)+' : '+e.Message+' -> Sql := TUniSQL.Create(nil);'); end; try Sql.Connection := Con; except on e: Exception do Log(FormatDateTime('dd.mm.yyyy hh:mm:ss.zzz', now)+' : '+e.Message+' -> Sql.Connection := Con;'); end; try Group := aGroup; except on e: Exception do Log(FormatDateTime('dd.mm.yyyy hh:mm:ss.zzz', now)+' : '+e.Message+' -> Group := aGroup;'); end; try Buf := aBuf; except on e: Exception do Log(FormatDateTime('dd.mm.yyyy hh:mm:ss.zzz', now)+' : '+e.Message+' -> Buf := aBuf;'); end; try Wnd := aWnd; except on e: Exception do Log(FormatDateTime('dd.mm.yyyy hh:mm:ss.zzz', now)+' : '+e.Message+' -> Wnd := aWnd;'); end; try FreeOnTerminate := true; except on e: Exception do Log(FormatDateTime('dd.mm.yyyy hh:mm:ss.zzz', now)+' : '+e.Message+' -> FreeOnTerminate := true;'); end; try Resume; except on e: Exception do Log(FormatDateTime('dd.mm.yyyy hh:mm:ss.zzz', now)+' : '+e.Message+' -> Resume;'); end; end;
Code:
Keine Zeile im Konstruktor löst die Exceptions aus, dessen Aufruf aber schon
25.07.2011 15:03:38.281 : Zugriffsverletzung bei Adresse 00000100. Lesen von Adresse 00000100 -> TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378
25.07.2011 15:04:18.718 : Zugriffsverletzung bei Adresse 00000100. Lesen von Adresse 00000100 -> TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 25.07.2011 15:05:02.859 : Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF -> TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 25.07.2011 15:08:05.062 : Zugriffsverletzung bei Adresse 00004244. Lesen von Adresse 00004244 -> TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 25.07.2011 15:08:37.375 : Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF -> TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 25.07.2011 15:09:19.812 : Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000 -> TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 25.07.2011 15:09:44.015 : Zugriffsverletzung bei Adresse 00003133. Lesen von Adresse 00003133 -> TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 ![]() ![]() Eeeedit...: Darauf steh ich ja. Jetzt, mit o.g. try-except Monster, treten nur noch die "weichen" Fehler auf, der Stack scheint auf einmal zu schnurren. Immer prima, wenn die Analyse die Ursache entfernt. Dabei ist das doch noch kein Quantencomputer ![]()
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
Geändert von Medium (25. Jul 2011 um 15:33 Uhr) |
![]() |
Registriert seit: 23. Jan 2008 3.687 Beiträge Delphi 2007 Enterprise |
#6
Zu früh gefreut. Ich hab nun mal jede Methode in einen try-except gefasst, um ganz genau zu sehen wo es ggf. noch knallen könnte. Zudem hab ich die Zykluszeit von 2s auf 300ms runter gesetzt, um meine Wartezeit zu verkürzen. Hier mein Log von 5 Testruns, die alle abbrachen. Eigentlich waren es 6, aber einer hat mir die IDE abgeschossen noch bevor ein Fehler im Log stand...
Code:
Edit: Auch hübsch, und neu:
25:07:2011 15:54:20:453: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 -> Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000
25:07:2011 15:54:30:906: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 -> Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF 25:07:2011 15:54:33:656: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 00C80000. Lesen von Adresse FFFFFFFF 25:07:2011 15:54:42:390: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 00000060. Lesen von Adresse 00000060 25:07:2011 15:54:43:234: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 -> Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000 25:07:2011 15:54:57:234: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 -> Stack-Überlauf -------------------------- 25:07:2011 15:56:05:156: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000 25:07:2011 15:56:08:687: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 -> Zugriffsverletzung bei Adresse 00CE51AB. Schreiben von Adresse B0CF1FD1 -------------------------- 25:07:2011 15:56:43:171: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 -> Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF 25:07:2011 15:56:43:250: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 00C80000. Lesen von Adresse FFFFFFFF 25:07:2011 15:56:46:468: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 -> Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF 25:07:2011 15:56:51:250: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000 25:07:2011 15:56:57:531: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Privilegierte Anweisung -------------------------- 25:07:2011 15:57:32:046: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 00C80000. Lesen von Adresse FFFFFFFF 25:07:2011 15:57:32:703: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000 25:07:2011 15:57:44:484: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 -> Zugriffsverletzung bei Adresse 00D04F10. Schreiben von Adresse 011609FD 25:07:2011 15:57:45:750: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF 25:07:2011 15:57:46:203: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 00C80000. Lesen von Adresse FFFFFFFF 25:07:2011 15:57:52:390: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 00000010. Lesen von Adresse 00000010 25:07:2011 15:58:02:125: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF 25:07:2011 15:58:08:562: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 -> Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000 25:07:2011 15:58:08:859: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 00000056. Lesen von Adresse 00000056 25:07:2011 15:58:09:546: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 00000056. Lesen von Adresse 00000056 25:07:2011 15:58:10:171: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 00000028. Lesen von Adresse 00000028 25:07:2011 15:58:13:000: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 00003134. Lesen von Adresse 00003134 25:07:2011 15:58:13:656: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 00004244. Lesen von Adresse 00004244 25:07:2011 15:58:17:390: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 -> Zugriffsverletzung bei Adresse 00D0BF7B. Schreiben von Adresse 7267758A 25:07:2011 15:58:28:812: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 -> Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF 25:07:2011 15:58:28:875: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF 25:07:2011 15:58:29:531: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 00000020. Lesen von Adresse 00000020 25:07:2011 15:58:33:453: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF 25:07:2011 15:58:34:312: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF 25:07:2011 15:58:34:984: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 000000FC. Lesen von Adresse 000000FC -------------------------- 25:07:2011 16:00:07:687: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 -> Zugriffsverletzung bei Adresse 00003832. Lesen von Adresse 00003832 25:07:2011 16:00:08:671: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 -> Zugriffsverletzung bei Adresse 0040399A in Modul 'Server.exe'. Lesen von Adresse FFFFFFFF 25:07:2011 16:00:12:062: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Zugriffsverletzung bei Adresse 00C80000. Lesen von Adresse FFFFFFFF 25:07:2011 16:00:12:578: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 -> Zugriffsverletzung bei Adresse 00C80000. Lesen von Adresse FFFFFFFF 25:07:2011 16:00:13:812: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=378 -> Zugriffsverletzung bei Adresse 00000297. Lesen von Adresse 00000297
Code:
Stacküberlauf, Privilegierte Anweisung (die ist auch mir neu an dieser Stelle), diverse Schreib- und Lesegriffe ins Klo und ein Totalzerriss der IDE... so langsam muss meine Frage eher lauten: Wie zum Geier schafft man es, eine derartige Vielfalt an Fehlern mit ein und dem selben Code, auf ein und der selben Datenbasis zu erzeugen!? Ich muss doch irgendwo ganz grundlegend etwas falsch machen, und hab nur Tomaten auf den Augen
25.07.2011 16:22:04.671: TDBEntryThread.Create(Qry.Connection, group, buf); Length(buf)=30 -> Externe Exception C000001D
![]() Darf ich eventuell einen Thread keinen weiteren Thread erzeugen lassen? Das wäre jetzt noch so mein vorerst letzter Anker. Es sieht alles so aus, als würde mein Programcounter bei Erstellung des Threads völlig im zufälligen Nirvana landen, aber ich fasse nichts via Gepointer oder anderen Kunstgriffen an. Hat das schon mal jemand gesehen? Wenn ja, wie/wo/wann? Mir fehlt ein Ansatz.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
Geändert von Medium (25. Jul 2011 um 16:25 Uhr) |
![]() |
Registriert seit: 7. Aug 2008 Ort: Brandenburg 1.487 Beiträge Delphi 12 Athens |
#7
Delphi-Quellcode:
Das ist so nicht nötig, der Thread startet in jedem Fall frühestens, wenn alle Konstruktoren abgeschlossen wurden.
constructor
begin inherited Create(true); {...tu was vor Execute...} Resume; end;
Delphi-Quellcode:
Ich vermute das die Exception im Konstruktor eigentlich nur ein Folgefehler und die Ursache viel früher zu suchen ist.
constructor
begin inherited Create(false); {...tu was vor Execute...} end; Problem: Es wird ein Thread erzeugt, der Zugriff auf eine Connection nimmt, die ihm nicht gehört. Es existiert keine Kontrolle welche Threads existieren, die derzeit mit dieser Connection arbeitet. Der Zugriff "Sql.Connection.InTransaction" kann schon eine Zugriffsverletzung auslösen. Es müsste zumindest unmittelbar ein StartTransaction folgen und beides mit einer CriticalSection gekapselt werden. Insgesamt scheint mir die Konstruktion ziemlich fehleranfällig. Ich würde die Anwendung im Prinzip so aufbauen: [1.Liste der wartenden Aufgaben] -> 1.Thread der jeweils eine Aufgabe per TCP/IP abarbeitet und mit dem Ergebnis in 2.Liste stellt (hat mit DB nichts zu tun) [2.Liste der wartenden Aufgaben] -> 2.Thread der jeweils die Datenbankarbeit für eine Aufgabe erledigt und diese mit neuem Termin wieder in die 1.Liste stellt (hat eigene DB-Verbindung, die niemanden sonst etwas angeht) Beide Threads existieren permanent und warten, wenn keine Aufgabe ansteht. Zugriffe auf die Listen müssen natürlich gekapselt werden. |
![]() |
Ansicht |
![]() |
![]() |
![]() |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
![]() |
![]() |