| Autor |
Beitrag |
ALF
      
Beiträge: 1085
Erhaltene Danke: 53
WinXP, Win7, Win10
Delphi 7 Enterprise, XE
|
Verfasst: Fr 30.07.10 20:06
Hi, dazu ein paar kurz Infos.
Die Formen werden zur Laufzeit als MDICHILD erstellt.
Der Thread als solches funktioniert innerhalb der Form.
Mein Problem ist, ich benötige die Daten aber schon wenn die Form erstellt wird!
Also meine Idee, im Oncreate-ereignis der Form. Mh.... und genau da will, oder kann es nicht funktionieren.
Die Daten werden vom Thread richtig gelesen, wenn es aber zum Abschluss der Procedure Synchronize kommt, kracht es mit EAccessViolation, schreiben von Adresse usw., obwohl die Daten in der Newform übertragen wurden.
Das ist die Procedure die Synchronize aufruft:
Delphi-Quelltext 1: 2: 3: 4:
| procedure TScanThread.UpdatePeaksTh; begin FNform.UpdatePeaks(FpeaksL, FpeaksR); end; |
als wenn die Procedure nicht mehr zurückfindet. Kann das sein??
Der Aufruf aus dem Thread erfolgt so:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| procedure TScanThread.Execute; var ..... ..... begin OutputDebugString('ich arbeite'); .... .... while (buflen > 0) and (not terminated) do begin ..... ..... end; OutputDebugString('Daten können abgeholt werden'); Synchronize(UpdatePeaksTh); .... .... OutputDebugString('ich beende mich'); Terminate; end; |
Beim kontollieren mit dem EreignisProtokoll kommt es bis 'Daten können abgeholt werden'
Eine Rückkehr der Procedure gibt es nicht!
Jemand ne Idee ob es so ist, wie ich vermute!
Wenn ja, was muss ich den da noch beachten?
Oder Liegt der Fehler ganz wo anders?
Gruss Alf
_________________ Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 30.07.10 20:13
ALF hat folgendes geschrieben : | | Mein Problem ist, ich benötige die Daten aber schon wenn die Form erstellt wird! |
Wie stellst du dir das vor? Das dauert schließlich kurz bis der Thread fertig ist. Und da ist dein OnCreate schon vorbei, du wirst die Daten also nie beim Erstellen selbst schon haben.
Wie erstellst und startest du denn den Thread? Kann es sein, dass du FreeOnTerminate benutzt? Wenn du da nicht aufpasst...
Und wo weist du die Formularvariable dem Thread zu? Im Konstruktor oder erst danach? (Wenn danach, musst du natürlich pausiert starten.  )
Ja, und dann ist noch die übliche Frage nach dem Ergebnis des Debuggers? Ist die Formvariable in der Zeile erreichbar?
Und natürlich: An welcher Adresse kommt denn die Zugriffsverletzung? Wenn die sehr klein ist, hast du nen Nullpointer, dann vermutlich die Formularvariable.
|
|
ALF 
      
Beiträge: 1085
Erhaltene Danke: 53
WinXP, Win7, Win10
Delphi 7 Enterprise, XE
|
Verfasst: Fr 30.07.10 20:56
jaenicke hat folgendes geschrieben : | | Wie stellst du dir das vor? Das dauert schließlich kurz bis der Thread fertig ist. Und da ist dein OnCreate schon vorbei, du wirst die Daten also nie beim Erstellen selbst schon haben. |
Beim Debuggen gebrüft, sind die Daten(es sind Arrays in der Form) schon gefüllt!
Also auch da, oder?
jaenicke hat folgendes geschrieben : | Wie erstellst und startest du denn den Thread? Kann es sein, dass du FreeOnTerminate benutzt? Wenn du da nicht aufpasst...
Und wo weist du die Formularvariable dem Thread zu? Im Konstruktor oder erst danach? (Wenn danach, musst du natürlich pausiert starten. ) |
mh... MainForm=MDIFORM
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| if OpenDialog1.Execute then begin .... .... NewForm:= TForm3.Create(self); end; |
TForm3:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| procedure TForm3.FormCreate(Sender: TObject); begin .... .... TScanThread.Create(mychan1, xzoom, self); end; ..... ..... procedure TForm3.UpdatePeaks(pL, pR: array of smallint); var i: integer; begin for i:= low(pL) to high(pL) do begin wavebufL[i]:= pL[i]; wavebufR[i]:= pR[i]; end;
timer1.Enabled:= true; end; |
Constructor des Threads
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| constructor TScanThread.Create(decoder: HSTREAM; zoom: integer; Nform: TForm3); begin inherited create(false); Priority:= tpNormal; FreeOnTerminate:= true; FDecoder:= decoder; FZoom:= zoom; FNform:= NForm; end; |
jaenicke hat folgendes geschrieben : | Ja, und dann ist noch die übliche Frage nach dem Ergebnis des Debuggers? Ist die Formvariable in der Zeile erreichbar?
Und natürlich: An welcher Adresse kommt denn die Zugriffsverletzung? Wenn die sehr klein ist, hast du nen Nullpointer, dann vermutlich die Formularvariable. |
Ja die Formvariable ist erreichbar.Die Arrays von TFORM3 werden ja gefüllt mit den Daten vom Thread. es Kracht ja auch beim 'end;' nicht bei 'FNform.UpdatePeaks(FpeaksL, FpeaksR)';
Also nach beenden von 'procedure TForm3.UpdatePeaks(pL, pR: array of smallint);'
1. Meldung: Z.verletzung bei Adresse 00401c19 in Modul Projekt.exe Schreiben von Adresse 000000001
2.Meldung EInvalidPointer ungültige Zeigeroperation!
Also das alte leiden, nicht einhalten von Grundsätzlichen Dingen! richtig?
Welche Möglichkeit habe ich aber dann, die Daten rechtzeitig zur verfügung zu haben, wenn nicht im Oncreate zu erstellen geht?
Gruss Alf
_________________ Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 31.07.10 08:58
Für diesen Beitrag haben gedankt: ALF
|
|
ALF 
      
Beiträge: 1085
Erhaltene Danke: 53
WinXP, Win7, Win10
Delphi 7 Enterprise, XE
|
Verfasst: Sa 31.07.10 10:10
Hi, und guten Morgen!
Jo vom Prinzip verstanden, die Erklärung ok.
Aber!! Ich vergass zu erwähnen das der Thread in einer anderen Unit liegt!
Also fang ich an alles zu modifizieren....., wenn ich es so machen will, soll.
Aber nun:
Egal wie ich es nun ansetzte. Entweder die Units kreuzen sich, was auch nicht geht, oder beim zuweisen von: newthread: TScanThread; wird TScanthread nicht gefunden, oder die Procedure von TForm3 zum abholen der Daten ist nicht bekannt!
Egal was ich nun versuche, es kommt immer eine Stelle die nicht zusammen passen will. Ich hab einfach keine Idee mehr
Selbst die Tuts, und alles was ich in den Foren gefunden habe, geben mir darauf keine Antwort!
Und alles nur, weil ich die Daten am Anfang schon benötige!
Gruss Alf
_________________ Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 31.07.10 10:17
ALF hat folgendes geschrieben : | | oder die Procedure von TForm3 zum abholen der Daten ist nicht bekannt! |
Das ist eigentlich auch nicht der richtige Weg. Stell in deinem Thread ein Event zur Verfügung, das dich benachrichtigt, wenn die Daten da sind, und hole die dann vom Formular aus ab. Der Thread sollte sowieso nicht wissen wohin die Daten sollen.
Denn der Thread hat nur den Sinn die Daten zu holen und bereitzustellen, mehr nicht.
Du kannst auch OnTerminate benutzen, aber mit einem eigenen Event hast du (für die Zukunft) auch die Möglichkeit zwischendrin Rückmeldungen zu geben.
Die Daten kannst du dann im Thread per Property bereitstellen. Da du den Aufruf des Events im Thread synchronisierst, kann der Hauptthread auch in dem Event darauf zugreifen. (Du kannst natürlich dem Event auch Parameter mitgeben, Sender sollte sowieso dabei sein.)
Für diesen Beitrag haben gedankt: ALF
|
|
ALF 
      
Beiträge: 1085
Erhaltene Danke: 53
WinXP, Win7, Win10
Delphi 7 Enterprise, XE
|
Verfasst: Sa 31.07.10 17:26
Ok habe nun alles neu gemacht, kann also jetzt unabhängig den Thread jetzt so aufrufen,
Dabei übergebe ich aber keine Form mehr!
Rückgabewert ist auch vorhanden
Delphi-Quelltext 1: 2: 3: 4:
| NewThread:= TscanThread.Create(...)
if NewThread.Binfertig then |
Schön, weiss nun aber immer noch nicht wie es weiter geht! Wo kommt die Abfrage hin?
mit dem Event naja, habe mir einiges angeschaut. Diese sind aber so Projektspeziell, das ein Rückschluss, auf mein Projekt, irgendwie nicht passt!?
Selbst wenn ich mir, nach den Vorbildern, ein Event zusammenschreibe, könnte ich damit erst mal nichts Anfangen, da ich nicht weiss wo setzte ich es ein.
Ich bekomme irgendwie nicht den zusammenhang hin, bezogen auf mein oncreate Problem!
Gruss Alf
_________________ Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 31.07.10 17:53
Also, als Beispiel: Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| public property Array1: ... property Array2: ... end;
private FMyThread; TMyThread;
FMyThread := ... FMyThread.OnTerminate := MyThreadTerminate;
procedure TMyForm.MyThreadTerminate(Sender: TObject); begin FMyThread.Array1 ... end; | Oder du erstellst dir nen Event: Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26:
| TMyUpdatePeaksEvent = procedure(Sender: TObject; pL, pR: array of SmallInt) of object;
...
public OnUpdatePeaks: TMyUpdatePeaksEvent read FOnUpdatePeaks write FOnUpdatePeaks;
...
if Assigned(FOnUpdatePeaks) then FOnUpdatePeaks(Self, MyArray1, MyArray2);
private FMyThread; TMyThread;
FMyThread := ... FMyThread.OnUpdatePeaks := MyThreadUpdatePeaks;
procedure TMyForm.MyThreadUpdatePeaks(Sender: TObject; pL, pR: array of SmallInt); begin pL... end; | Erstellen kannst du den Thread ruhig in OnCreate des Formulars und freigeben entsprechend später in OnDestroy.
Für diesen Beitrag haben gedankt: ALF
|
|
ALF 
      
Beiträge: 1085
Erhaltene Danke: 53
WinXP, Win7, Win10
Delphi 7 Enterprise, XE
|
Verfasst: Sa 31.07.10 18:21
Ja, an so was habe ich mich versucht und bin dann da gescheitert!
In der Unit Thread:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
| type TMyUpdatePeaksEvent = procedure(Sender: TObject; pL, pR: array of SmallInt) of object;
type TScanThread = class(TThread) private Fdecoder: HSTREAM; Fzoom: integer; Fsec: integer; FpeaksL: array of smallint; FpeaksR: array of smallint; FBinfertig: Boolean; FOnUpdatePeaks: array of smallint; protected procedure Execute; override; procedure SetBinfertig(const Value: Boolean); public constructor Create(decoder: HSTREAM; zoom: Integer; sec: integer); property Binfertig: Boolean read FBinfertig default False; property OnUpdatePeaks: TMyUpdatePeaksEvent read FOnUpdatePeaks write FOnUpdatePeaks; end; |
jetzt bekomme ich, auch vorhin wo ich es mit meinem eigenem event TDatenholen versucht habe, ne Fehlermeldung:
[Fehler] Unit2.pas(29): Inkompatible Typen: 'dynamic array' und 'TMyUpdatePeaksEvent' oder ebend TDatenholen. Hatte ich es also wieder verworfen!
Weiss zwar was die FehlerMeldung bedeutet, weiss aber nicht was ich ändern muss!!
Sorry für C&P
Gruss Alf
_________________ Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 31.07.10 18:25
Naja, fast... Delphi-Quelltext 1:
| FOnUpdatePeaks: TMyUpdatePeaksEvent; | Schließlich hast du die Property auch mit diesem Typ deklariert...
Für diesen Beitrag haben gedankt: ALF
|
|
ALF 
      
Beiträge: 1085
Erhaltene Danke: 53
WinXP, Win7, Win10
Delphi 7 Enterprise, XE
|
Verfasst: Sa 31.07.10 19:08
Ich verzweifle
EAccessViolation: schreiben von Adresse 000000001
Aber nur in der IDE!
Starte ich das ohne, keine Fehler!?(noch nicht auf ein anderen Rechner gestestet)
Habe zum Test mal die Freigabe der dynamischen Arrays im Thread auskommentiert, oops keine Fehler mehr, auch in der IDE!
Habe ich die zu früh freigegeben? Hier mal Thread.execute.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26:
| procedure TScanThread.Execute; var PeakBuf: array[0..176400] of integer; ..... ..... begin inherited; try
setlength(FpeaksL, 2600); setlength(FpeaksR, 2600); ..... ..... OutputDebugString('Daten können abgeholt werden'); FBinfertig:= True; Synchronize(UpdatePeaksTh); finally
OutputDebugString('ich beende mich'); Terminate; end; |
Gruss Alf
_________________ Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 31.07.10 19:13
In welcher Zeile tritt der Fehler denn auf? Kann es sein, dass du von außen noch auf ein Array im Thread zugreifst?
Wie sind die Arrays denn deklariert? Mich irritiert das := nil etwas. 
|
|
ALF 
      
Beiträge: 1085
Erhaltene Danke: 53
WinXP, Win7, Win10
Delphi 7 Enterprise, XE
|
Verfasst: Sa 31.07.10 19:21
An welcher Stelle, wie beim Anfang!
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| procedure TScanThread.UpdatePeaksTh;begin if Assigned(FOnUpdatePeaks) then FOnUpdatePeaks(Self, FpeaksL, FpeaksR);
end; |
nach dem abholen der Daten.
Schau mal 2 Posts weiter hoch von mir, da steht wie TScanThread erstellt wird mit den Arrays:
FpeaksL: array of smallint;
FpeaksR: array of smallint;
Gruss Alf
_________________ Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 31.07.10 19:31
Das hatte ich schon so verstanden, aber da dann der Code nicht viel Sinn macht, habe ich nochmal nachgefragt.
Es reicht schon die Länge auf 0 zu setzen.
Ja, so sehe ich an dem geposteten Code erstmal auch nix außergewöhnliches. FreeOnTerminate und sowas hattest du ja deaktiviert, oder?
|
|
ALF 
      
Beiträge: 1085
Erhaltene Danke: 53
WinXP, Win7, Win10
Delphi 7 Enterprise, XE
|
Verfasst: Sa 31.07.10 20:21
Jo, FreeOnTerminate:= false, sonst krachts auch an der Stelle!!
Sobald ich,
setlength(FpeaksL, 0);
setlength(FpeaksR, 0);
wieder drin hab krachts.
Also muss ich was anderes machen für die Freigabe oder?
Nur komischer weise passiert das nur wenn der Thread im oncreate aufgerufen wird!
Im Programm selber (TForm3) brauche ich den Thread ja auch, also nach create newform;
Da kann es so stehen, setlength(FpeaksL, 0) und nichts passiert!??? Selbst FreeOnTerminate:= True, macht da nix.
Fragen über Fragen, ich weiss, aber wenn man als Anfänger mit sowas (wiedersprüchliches) konfrontiert wird
Ich bedanke mich für die super Aussdauer mit mir
Hab auf alle Fälle mehr gelernt, als xTage in allen Foren suchen(was ich ja gemacht habe) und nix finden
Ich lass die Freigabe erst mal weg, sonst komm ich nie weiter!!
Edit1: Freigabe der Arrays muss gemacht werden, sonst StackOverFlow  (dyn. Arrays)
Edit2:Feststellung!! Solange die Form in eine Initialisierung steckt kann man keinen Thread starten  (Kann man schon, aber nicht mit dyn.Arrays)
Gruss Alf
_________________ Wenn jeder alles kann oder wüsste und keiner hätt' ne Frage mehr, omg, währe dieses Forum leer!
|
|
|