Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - invalid Pointer
ALF - Mi 01.09.10 21:09
Titel: invalid Pointer
Hi, nachdem ich versucht habe mein prog ein bischen "schneller/effizienter" zu machen :mrgreen: ,
man beachte die "" ,erhalte ich bei bestimmten Situationen diese Fehlermeldung!
Nach dem ich nun versucht habe mit exeptions die Fehlermeldung zu lokalisieren, was teilweise auch gelang, kommt halt nur noch diese Meldung. Passieren tut dies aber nur, wenn bei onresize die
Form kleiner gemacht wird und dies auch wieder nur unter bestimmten Umständen.
Jetzt wird es schwer dies genau zu erklären!!! :gruebel:
dazu mal den Code im onresize:
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: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113:
| procedure TForm3.FormResize(Sender: TObject); begin
finalize(wavebufL); finalize(wavebufR);
buf:= Width - Panel2.Width - Panel3.Width;
setlength(wavebufL, buf); setlength(wavebufR, buf);
if (length(wavebufL) = buf) and (length(wavebufR) = buf) then begin
BASS_ChannelSetPosition(mychan1, BASS_ChannelSeconds2Bytes(mychan1, xpos), BASS_POS_BYTE);
NewThread:= TScanThread.Create(mychan1, xzoom, buf); Newthread.OnUpdatePeaks := MyThreadUpdatePeaks; end;
DrawLevelLine;
end
procedure TScanThread.Execute; var PeakBuf: array[0..10400] of integer; Data: ^smallint; rc: integer; pl, pr: integer; BufLen: Integer; counter: integer; msec: real; begin inherited; try
OutputDebugString('ich arbeite'); counter:= 0; pl:= 0; pr:= 0; rc:= Fzoom; msec:= 0; setlength(FpeaksL, Fbuf); setlength(FpeaksR, Fbuf); BufLen:= Bass_ChannelGetData(Fdecoder, @PeakBuf, 10400); Data:= @PeakBuf;
while (buflen > 0) do begin while rc >= 1 do begin if (Data^) > pl then pl:= (Data^) else if ((Data^) < pl) and (Fzoom < 6) then pl:= (Data^); Inc(Data);
if (Data^) > pr then pr:= (Data^) else if ((Data^) < pr) and (Fzoom < 6) then pr := (Data^); Inc(Data);
BufLen:= BufLen -4 ;
if BufLen <= 0 then begin msec:= msec + 0.0585; BASS_ChannelSetPosition(Fdecoder, BASS_ChannelSeconds2Bytes(Fdecoder, msec), BASS_POS_BYTE); BufLen:= Bass_ChannelGetData(Fdecoder, @PeakBuf, 10400);
Data:= @PeakBuf; end; dec(rc); end; if (counter > High(FpeaksL)) or (counter > High(FpeaksR)) then break; FpeaksL[counter]:= pl; FpeaksR[counter]:= pr; inc(counter); pl:= 0; pr:= 0; rc:= trunc(power(2, Fzoom )); end;
OutputDebugString('Daten können abgeholt werden'); Synchronize(UpdatePeaksTh);
FBinfertig:= True; finalize(FpeaksL); finalize(FpeaksR); except
on E: Exception do ErrorPop('Fehler im thread!'); end;
OutputDebugString('ich beende mich'); Terminate;
end; |
Jetzt der Versuch es zu erklären: es passiert nur, wenn die darstellung der Daten kleiner ist als die Form und dann auch nur, wenn die Form weiter kleiner gemacht wird!
Meine Frage, wie kann ich jetzt eventuell feststellen an welcher Stelle es genau passiert und warum?
Gruss Alf
Flamefire - Mi 01.09.10 21:27
finalize würde ich weglassen, könnte der fehler sein
dann klären, was du mit setlength funktioniert nicht meinst
und dann prüfen, ob buf<=0 ist
ALF - Mi 01.09.10 21:53
mh..
buf wird nicht kleiner als 0, weil die Form nicht gegen 0 pixel geht(incl der Panels)
Im onresize habe ich mal finalize raus genommen. Gleicher Fehler!
Flamefire hat folgendes geschrieben : |
| dann klären, was du mit setlength funktioniert nicht meinst |
Wenn ich die If Abfrage nicht rein mache kracht es auch an der Stelle!!!
Wahrscheinlich ist das resize zu schnell?
Habe aber fest gestellt, wenn ich die Form pixel für pixel kleiner mache passiert nichts(also sehr Zeitaufwendig :mrgreen: !!! Nur wenn man die Form, so wie man sie kleiner macht, Maus linke Taste und schieben, peng, dan passiert es! Aber auch
nur, wenn die Daten kommplett angezeigt werden! Dies macht mich ja so Stutzig!!!! Wenn die daten gestreckt sind, kann ich die Form resizen ohne Probleme. Ich weiss nur nicht wie ich den Fehler noch Abfangen kann um zu wissen wo es passiert!?
Gruss Alf
Flamefire - Do 02.09.10 13:21
hm. du erstellst beim resizen immer nen neuen thread. die alten scheinen noch weiterzulaufen.
und finalize würde ich nirgends verwenden. auch nicht im thread. lass das den delphi compiler machen und verwende nur setlength.
ALF - Do 02.09.10 13:56
Flamefire hat folgendes geschrieben : |
| hm. du erstellst beim resizen immer nen neuen thread. die alten scheinen noch weiterzulaufen. |
Das ganze funct ja, auch als ich bei meiner alten variante, grössere Arrays hatte, konnte ich den Thread mit den Scrollbalken ganz schnell hin und her zoomen, da wurden die Threads hintereinander abgearbeitet, wenn auch dann bei maxzoom mit >1s verzögerung die Daten aktuallisiert wurden.
Allerdings war der Thread aufruf nicht im onresize!
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| PeakBuf: array[0..10400] of integer; if BufLen <= 0 then begin msec:= msec + 0.0585; BASS_ChannelSetPosition(Fdecoder, BASS_ChannelSeconds2Bytes(Fdecoder, msec), BASS_POS_BYTE); BufLen:= Bass_ChannelGetData(Fdecoder, @PeakBuf, 10400); Data:= @PeakBuf; end; |
Flamefire hat folgendes geschrieben : |
| und finalize würde ich nirgends verwenden. auch nicht im thread. lass das den delphi compiler machen und verwende nur setlength. |
Im Thread selbst muss ich zum Schluss finalize machen sonst Stackoverflow :wink: bei dynamichen Arrays.
Selbst ohne IDE kommt es zur Meldung. Wenn ich dann wegklicke, kann ich weitermachen und irgendwann kommt es dann natürlich zum Absturz :?
Selbst wenn ich dann den Debugger anschaue, steht es irgendwo im Programm, aber an welcher Zeile oder welche Variable es betrifft, das kann ich nicht erkennen, leider!
Denn sonst könnte ich die Variablen evtl Absichern, das die geforderte grösse auch vorhanden ist wie ich es im onresize schon gemacht habe.
Oder ne andere Lösung finden, aber welche :gruebel:
Gruss Alf
Flamefire - Do 02.09.10 14:06
dann läuft da echt was falsch. sieht sehr nach synchronisierungsproblemen aus.
finalize sollte da echt nicht nötig sein.
zu dem Erstellen:
Du erstellst einen Thread mit buf=100, der läuft
größenänderung: thread erstellen mit buf=50
100er-Thread wird fertig-->Schreibt zuviele Daten, da ja Größe nicht stimmt!
Zeig mal deine UpdatePeaksTh
ALF - Do 02.09.10 14:21
jo
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TScanThread.UpdatePeaksTh; begin try if Assigned(FOnUpdatePeaks) then FOnUpdatePeaks(Self, FpeaksL, FpeaksR); except on E: Exception do ErrorPop('fehler synchronize!'+ inttostr(high(FpeaksL))); end; OutputDebugString('daten lesen beendet'); end; |
und in der Form3 ist dieses dann
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| procedure TForm3.MyThreadUpdatePeaks(Sender: TObject; pL, pR: array of SmallInt); var i: integer; begin try for i:= low(pL) to high(pR) do begin wavebufL[i]:= pL[i]; wavebufR[i]:= pR[i]; end; except on E: Exception do ErrorPop('Fehler im Updatepeaks!'); end;
OutputDebugString('Daten gelesen'); DrawPeaks; formpaint(self); end; |
Wie gesagt, ich weiss ja noch nicht mal ob der Fehler im Thread auftritt. Ich vermute es einfach!
Gruss Alf
Flamefire - Do 02.09.10 14:27
Wie vermutet:
Delphi-Quelltext
1: 2:
| setlength(wavebufL, buf); setlength(wavebufR, buf); |
aber schreiben tust du die länge die die arrays im thread haben.
schalt mal bereichsprüfungen ein. dann wirft er dir dort den fehler.
ALF - Do 02.09.10 15:00
ne, ne Schau mal im ersten Post, buf ist bei der Übergabe,im Thread =Fbuf
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| NewThread:= TScanThread.Create(mychan1, xzoom, buf); ..... ..... setlength(FpeaksL, Fbuf); setlength(FpeaksR, Fbuf); |
Bereichsüberprüfung ist an, kommt trotzdem nur invalid Pointer
Wie schon mal erwähnt. Der Fehler kommt nur wenn xzoom den Maxwert hat und nur beim kleiner machen(x-achse) der Form!!! Beim grösser machen der Form(x-achse)wird buf ja auch grösser), da wird ja auch alles so aufgerufen wie es drin steht, im onresize, ohne das ein Fehler kommt :?
Und das macht mich ja so stutzig!
Gruss Alf
delfiphan - Do 02.09.10 15:32
Du zeigst ja nur die Hälfe der Geschichte... Aber du scheinst nicht sicherzustellen, dass du nicht mehrere Threads offen hast, die auf die gleichen Daten schreiben. Wenn du das Fenster grösser und kleiner machst, werden vermutlich ganz viele parallele Threads geöffnet.
Und: Lässt Bass zu, dass du so Sachen in Threads machst?
Flamefire - Do 02.09.10 16:28
richtig das meine ich:
du startest nen Thread mit maximaler größe (Length(FPeaks)=100)
dann machst du es kleiner bevor der 1. thread fertig ist: (Length(waveBuf)=50)
dann wird der 1.thread fertig:
Delphi-Quelltext
1: 2: 3: 4: 5:
| for i:= low(pL) to high(pR) do begin wavebufL[i]:= pL[i]; wavebufR[i]:= pR[i]; end; |
wie gesagt: das mit dem finalize sollte nicht nötig sein
und dass setlengt "nicht geht" kling wirklich wie, als setzt du die länge merhfach gleichzeitig (in mehreren threads)
ALF - Do 02.09.10 17:51
delfiphan hat folgendes geschrieben : |
| Du zeigst ja nur die Hälfe der Geschichte... Aber du scheinst nicht sicherzustellen, dass du nicht mehrere Threads offen hast, die auf die gleichen Daten schreiben. Wenn du das Fenster grösser und kleiner machst, werden vermutlich ganz viele parallele Threads geöffnet. |
mh... Ich habe ja extra mal das Ereignisprotokoll mit laufen(OutputDebugString) um zu sehen ob evtl Threads nachhängen nein. Selbst wenn man ganz langsam die Form verkleinert(x-Achse)also jder thread die Meldung ausgibt "Ich beende mich") machts peng!
Warum aber nicht wenn ich vergrössern(x-Achse) tue? Dann werden die Arrays auch verändert und der Thread xmal gestartet!
delfiphan hat folgendes geschrieben : |
| Und: Lässt Bass zu, dass du so Sachen in Threads machst? |
kein Problem damit, selbst beim Scrollen(x-Achse) hat Bass keine Probleme!
Flamefire hat folgendes geschrieben : |
richtig das meine ich:
du startest nen Thread mit maximaler größe (Length(FPeaks)=100)
dann machst du es kleiner bevor der 1. thread fertig ist: (Length(waveBuf)=50)
dann wird der 1.thread fertig: |
und warum nur beim verkleinern der Form?
Wenn ich die Form auf 2Bildschirme vergrössere, passiert nix :gruebel:
Flamefire hat folgendes geschrieben : |
| und dass setlengt "nicht geht" kling wirklich wie, als setzt du die länge merhfach gleichzeitig (in mehreren threads) |
Der Fehler den ich im onresize erhalten hatte war, das manchmal wavebufl, zum Beispiel -1 war!? Darum dort jetzt die If abfrage! So sichere ich wenigstens an der einen Stelle das buf und wavbufl gleich gross sind!
Ausser im Thread, habe ich finalize im onresize rausgenommen! Ändert aber nix.
Gruss Alf
platzwart - Do 02.09.10 17:56
ALF hat folgendes geschrieben : |
| und warum nur beim verkleinern der Form? |
Das klingt für mich so: Beim Vergrößern wird dein Array größer. Also passiert nix, wenn ich die "alte Länge ablaufe". Beim Verkleinern schon, weil dann die letzten Elemente nicht mehr existieren. Nur so ein Bauchgefühl...
platzwart - Do 02.09.10 17:59
Delphi-Quelltext
1: 2: 3: 4: 5:
| for i:= low(pL) to high(pR) do begin wavebufL[i]:= pL[i]; wavebufR[i]:= pR[i]; end; |
>>>
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| for i:= low(pL) to high(pL) do begin wavebufL[i]:= pL[i]; end;
for i:= low(pR) to high(pR) do begin wavebufR[i]:= pR[i]; end; |
Dann immer noch BUMM? Einfach mal testen...
Flamefire - Do 02.09.10 18:10
ja dann immernoch...
wie wäre es mit nem
Delphi-Quelltext
1: 2: 3: 4: 5:
| for i:= low(pL) to Min(high(pR),high(wavebufL)) do begin wavebufL[i]:= pL[i]; wavebufR[i]:= pR[i]; end; |
ALF - Do 02.09.10 18:52
he Leute das kann doch wohl nicht wahr sein
@Flamefire seine Variante Perfekt :beer: keine Probleme mehr 8)
Auf sowas muss man aber erst mal kommen!
Danke an euch beiden
Nun kann ich weiter versuchen das ganze noch effizienter zu machen :lol:
Auch wenn ich null Ahnung habe.
Gruss Alf
Flamefire - Do 02.09.10 21:24
gut dann ist das behoben. aber nur an der wirkung
jetzt noch bitte die ursache beheben: dass du mehrere threads hast die auf unsynchrone daten zugreifen (in dem Fall die unterschiedlichen Längen der Arrays)
ALF - Do 02.09.10 21:43
hee, ja, Verstanden schon was Du meinst. Nur, wenn es zu keiner Exeption mehr kommt und es kein Daten überlauf gibt. Wo soll ich jetzt was ändern oder sichern das nix weiter passiert?
Leider ist mein Erfahrungschatz da mehr auf das einfache Coden begrenzt, als das ich jetzt wüsste an welcher Stelle ich da ansetzen müsste!?
Gruss Alf
delfiphan - Do 02.09.10 21:54
In einem Thread solltest du entweder nur auf lokale Variablen oder gelockte Daten zugreifen. Nur wenn das Design so konzipiert ist, dass ein Fremdzugriff ausgeschlossen ist - oder du genau weisst, was du tust - kannst du ungelockt auf Daten zugreifen.
Folgendes Design wär eine Möglichkeit.
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:
| procedure TScanThread.Execute; var PeaksL, PeaksR: array of ...; begin SetLength(PeaksL, ...); SetLength(PeaksR, ...);
FCriticalSection.Enter; try FPeaksL := PeaksL; FPeaksR := PeaksR; PeaksL := nil; PeaksR := nil; finally FCriticalSection.Leave; end;
Synchronize(...);
end; |
Entsprechend
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure TScanThread.UpdatePeaksTh; begin if Assigned(FOnUpdatePeaks) then begin FCriticalSection.Enter; try FOnUpdatePeaks(Self, FPeaksL, FPeaksR); finally FCriticalSection.Leave; end; end; end; |
FCriticalSection musst du im Konstruktor erzeugen und im Destruktor wieder freigeben.
Flamefire - Do 02.09.10 22:20
öhm. nein das ist nicht das richtige.
da die variablen private variablen des threads sind, sind die "gelockt". nur der eine thread kann da drauf zugreifen -->alles ok
Wichtiger ist wirklich, zu verhindern, dass ein fertiger thread daten eines anderen formats (länge) schreiben will
-->vorm resize alle threads beenden, bestätigen lassen (waitfor), dann länge ändern, dann thread starten
warum es bei dir knallt:
resizeevent wird wärend des resizes häufig aufgerufen (AFAIK)--> du hast nen haufen threads laufen. alle denken, die ham die richtige länge.
Wenn du also threads abschießen kannst (also egal ist, wenn mal daten fehlen) dann tu das.
ansonsten ist das mit dem min() schon ganz gut.
BTW:besser ist es, nicht ständig den thread neu zu erzeugen. weil sonst:
thread 1 arbeitet musik von 0-10
thread 2 arbeitet musik von 7-18
usw...
du hast dann also überlappungen. besser wäre, dem thread nachrichten zu schicken wie "ab nächstem durchlauf nur noch x werte" und den thread die ganze zeit laufen lassen.
delfiphan - Do 02.09.10 23:12
Ok, meinen Post oben bitte ignorieren ;)
ALF - Do 02.09.10 23:21
jetzt hast Du mich aber richtig Nervös gemacht. War schon am Suchen mit CS wie man das umsetzt :shock:
Das andere habe ich mir auch schon überlegt, bin aber wieder davon abgegangen. Warum weiss nicht mehr. Oder ich habs nicht hinbekommen oder zu viele Baustellen in meinem Prog.
Anbei, es ist die Darstellung der Wavform, von der kleinsten machbaren Anzeige bis zu kompletten Datei.
Werd aber Deine Vorschläge versuchen umzusetzen :wink:
Gruss Alf
delfiphan - Fr 03.09.10 00:15
Ja, ich hatte irgendwie im Kopf, dass FPeaksR/FPeaksL ausserhalb liegen und alle irgendwie darauf zugreifen. Wieso weiss ich jetzt auch nicht mehr. Wahrscheinlich, weil mit diesen Daten gezeichnet wird.
ALF - Fr 03.09.10 11:06
So, hab mal folgendes gamacht im Onresize
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| procedure TForm3.FormResize(Sender: TObject); begin if Assigned(NewThread) then if not NewThread.Binfertig then NewThread.Binfertig:= true;
..... ..... end; |
und im thread.execute dann
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| while (buflen > 0) and (not terminated) do begin while rc >= 1 do begin if Fbinfertig then terminate; ..... ..... end; ..... ..... end; |
funktioniert auch. Ist aber noch nicht das gelbe vom Ei :roll:
Gruss Alf
delfiphan - Fr 03.09.10 13:19
Du kannst auch einfach
Delphi-Quelltext
1:
| FreeAndNil(NewThread); |
schreiben. Der setzt dann Terminated auf True und wartet, bis der Thread beendet ist (dieses Warten fehlt bei dir noch).
ALF - Fr 03.09.10 16:51
Jo, hab es mal so umgesetzt:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| procedure TForm3.FormResize(Sender: TObject); begin if Assigned(NewThread) then begin if not NewThread.Binfertig then begin NewThread.Terminate; NewThread.WaitFor; FreeAndNil(NewThread); end; end; .... .... end; |
aber schneller ist es auch nicht. Hatte gehofft das es etwas schneller geht als meine Version :wink:
Sieht aber besser aus und man erkennt was gemacht wird. Bei meiner müsste man erst schauen warum ich es so mache :)
BIG THX für Deine Ausdauer :D
Gruss Alf
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!