Registriert: Mo Sep 02, 2002 15:41 Beiträge: 867 Wohnort: nahe Stuttgart
Hey,
ich habe zur Zeit ein Problem mit einem Thread, in den ich Berechnungscode ausgelagert habe. Der Thread soll dazu da sein, dass er bequem per QPC mit delta t im µs- bis ms-Bereich rechnen kann.
Momentan ist meine Lösung die folgende:
Der VCL-Thread enthält alle Daten;
sobald benötigt, wird der Rechnerthread angeschmissen und liest, rechnet, schreibt mit diesen Daten, die im VCL-Thread nicht angefasst werden... (Zumindest bis jetzt, denn theoretisch würde ich gerne Veränderungen an den Daten vornehmen, was aber das gleiche Problem ist, wie unten erzählt).
Davon abgesehen werden sie für die Ausgabe ausgelesen.
D.h. der Rechenthread soll solange rechnen, bis ihn der VCL-Thread anhält, um kurz die Daten zu verarbeiten. Mein Wunschdenken war:
Code:
procedure Draw;
begin
fThread.Suspend;
whilenot fThread.SuspendeddoSleep(0);// falls überhaupt notwendig bzw. Auswirkung
// Zeichnen
fThread.Resume;
end;
Damit kriege ich aber hin und wieder nen netten Threadfehler ("Im Projekt First.exe ist eine Exception der Klasse EThread mit der Meldung 'Thread-Fehler: Zugriff verweigert (5)' aufgetreten.").
Nun ist mir nicht ganz klar, wie ich das eigentlich verhindern soll. So wie ich das verstanden habe, sorgt eine CriticalSection nicht dafür, dass alle anderen Threads angehalten werden, sondern nur, dass ein bestimmter Code/Prozedur nur von einem Thread verarbeitet werden darf, was mir ja nicht weiterhilft, da ich gerne die Daten und nicht den Code schützen würde. Auch Synchronize arbeitet vom Rechenthread zum VCL-Thread, aber laut OH nicht umgekehrt.
Hab ich hier nen Designfehler drin oder liegt der Grund für den Fehler womöglich noch woanders?
Außerdem: Ich möchte, dass der Thread die Daten auch über ein Event individuell bearbeitbar macht. Kann ich aus dem Thread heraus dann problemlos einen Eventhandler of object callen, der im "VCL-Thread-Code" liegt, wenn der Eventhandler nur mit den übergebenen Daten arbeitet? Oder funktioniert das nur mit Synchronize; oder sollte man den Thread so gestalten, dass man in einer Ableitung eine Prozedur überschreibt und dann mit der abgeleiteten Instanz arbeitet?
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Wegen dem Synchronisieren, das, was du mit Suspendet versuchst: Dort sind Mutexes / Critical Sections das Mittel der Wahl. Du würdest den Mutex für alle für das rendern benötigten Daten beim starten des Rendervorgangs einfach Locken. Das führt dazu, dass der VCL-Thread so lange wartet, bis der aktuelle "Sperrer" des Mutexes die Sperrung aufhebt. Im Rechenthread würdest du dann den Mutex immer dann sperren, wenn du Daten, die fürs Rendern gebraucht werden könnten, ausliest oder schreibst. Du darfst halt nicht vergessen, das ganze zu Entsperren, wenn du durch bist.
Das mit dem Suspend und Resume kann auch massiv schief gehen. Zum beispiel, wenn dein Thread gerade dabei ist einen großen Wert oder mehrere Kleine zu updaten. Du rufst mitten drin Suspend auf. Gehen wir mal von einem Physik-Thread aus, der gerade die Bewegungsrichtung eines Objektes ändert. Er schreibt die neue X-Richtung, dann die neue Y-Richtung, dann wird er vom VCL-Thread mittels Suspend unterbrochen, d.h. du hast beim Rendern die X und Y ausrichtung aktualisiert, Z dagegen ist noch nicht aktuell... Könnte komisch wirken.
Was die Events betrifft, bleibt dir nur Synchronize;.
Gruß Lord Horazont
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Daten (Speicherbereiche) direkt schützen geht nicht. Du kannst lediglich verhindern, dass Code mehrfach ausgeführt wird der darauf zugreift. Das könnte man mit einer Mutex/Semaphore/CriticalSection realisieren können.
Aber dein Code sieht für mich jetzt so aus, dass immer irgendjemand darauf zugreifen muss. Entweder zum Berechnen/Verändern oder zum Zeichnen. Wenn du jetzt die Speicherbereiche blockierst, dann erzeugst du recht wahrscheinlich eine Situation in der der Speicher sehr häufig und lange gelockt ist. Und damit arbeitest du ganz stark gegen das Prinzip von Threads.
Lesende Zugriffe sind ungefährlich solange nicht gleichzeitig geschrieben wird. Diese Tatsache würde ich versuchen so häufig auszunutzen wie es geht. Ich würde vermutlich eher ein Design anstreben bei dem du zum Zeichnen nichts blockieren musst. Allerdings kenne ich die Randbedingungen und die Schwerpunkte deiner Anwendung nicht. Wie groß ist denn der Speicher und was berechnest du? Wie häufig zeichnest du denn?
Eine Möglichkeit könnte folgende sein. Das Zeichnen und die Grundlage für die Berechnung im Thread könnte der Speicherbereich aus dem VCL Thread sein. Der Thread legt seine Ergebnisse aber in einem seperaten Buffer ab. Wenn er fertig ist ruft er mittels Synchronize eine Methode auf die die Ergebnisse in den VCL Speicher schreibt. Dann läuft die Berechnung im Thread ab und der VCL Thread hat immer einen gültigen Speicher zum Zeichnen. Du hast aber mehr Speicherverbrauch. Ob so was für dich in Frage kommt weiß ich aber nicht, da ich die Rahmenbedingungen nicht kenne.
PS: Zu dem Eventproblem. Jedes mal, wenn du Synchronize oder andere Lockings benutzt, erzeugst du eine Situation in der es passieren kann, dass einer warten muss. Und das sollte man so gut wie möglich vermeiden. Außerdem erhöht sich die Chance auf Deadlocks. Das Beste ist da meistens immer es im Thread auszuführen. Aber auch da. Ich kenne die Rahmenbedingungen nicht und es kann sein, dass es für deinen Fall eher nicht praktikabel ist. Muss ja außerdem auch in dein Anwendungsdesign passen.
Registriert: Mo Sep 02, 2002 15:41 Beiträge: 867 Wohnort: nahe Stuttgart
Lossy eX hat geschrieben:
Daten (Speicherbereiche) direkt schützen geht nicht. Du kannst lediglich verhindern, dass Code mehrfach ausgeführt wird der darauf zugreift. Das könnte man mit einer Mutex/Semaphore/CriticalSection realisieren können.
Aber dein Code sieht für mich jetzt so aus, dass immer irgendjemand darauf zugreifen muss. Entweder zum Berechnen/Verändern oder zum Zeichnen. Wenn du jetzt die Speicherbereiche blockierst, dann erzeugst du recht wahrscheinlich eine Situation in der der Speicher sehr häufig und lange gelockt ist. Und damit arbeitest du ganz stark gegen das Prinzip von Threads.
Ich hab jetzt auch rausgefunden, dass ich das nicht ganz kapiert hab. Ich dachte, eine Instanz einer CriticalSection kann man nur an einer Code-Stelle verwenden. Ebenso fand ich raus, dass ein Mutex lediglich eine prozessübergreifende CriticalSection ist, was ich hier irgendwie nirgends gefunden hab. Mir ging es im Grunde einfach darum, die Berechnung vom langsamen Zeichenthread abzukoppeln. Siehe unten:
Zitat:
Lesende Zugriffe sind ungefährlich solange nicht gleichzeitig geschrieben wird. Diese Tatsache würde ich versuchen so häufig auszunutzen wie es geht. Ich würde vermutlich eher ein Design anstreben bei dem du zum Zeichnen nichts blockieren musst. Allerdings kenne ich die Randbedingungen und die Schwerpunkte deiner Anwendung nicht. Wie groß ist denn der Speicher und was berechnest du? Wie häufig zeichnest du denn?
Das Ganze ist ein Partikelsystem mit derzeit 16k Partikeln. Jedes Partikel müsste etwa 44 Bytes benötigen, also grob 721 KB Speicheraufwand. Gezeichnet wird mit VSync-üblichen 60 bis 80Hz. Das Problem ist, die Einwirkung auf Geschwindigkeit habe ich derzeit über Kräfte bzw. Beschleunigungen realisiert. a = dv/dt, ebenso v = ds/dt ... dt, also die Zeitschritte sollten für die Näherung also so klein wie nur möglich werden... Mit dem 60Hz-Renderthread lieg ich dann bei 17ms, mit dem CriticalSection-Thread jetzt bei 16k Partikeln immer noch bei 1.5ms. Das klingt eigentlich nicht nach viel, hat aber hatte ich mit dem Renderthread schon seltsame Partikelhäufungen und Voids.
Zitat:
Eine Möglichkeit könnte folgende sein. Das Zeichnen und die Grundlage für die Berechnung im Thread könnte der Speicherbereich aus dem VCL Thread sein. Der Thread legt seine Ergebnisse aber in einem seperaten Buffer ab. Wenn er fertig ist ruft er mittels Synchronize eine Methode auf die die Ergebnisse in den VCL Speicher schreibt. Dann läuft die Berechnung im Thread ab und der VCL Thread hat immer einen gültigen Speicher zum Zeichnen. Du hast aber mehr Speicherverbrauch. Ob so was für dich in Frage kommt weiß ich aber nicht, da ich die Rahmenbedingungen nicht kenne.
Hab ich damit dann noch den Geschwindigkeitsvorteil? Soweit ich gehört und gedacht habe, wird Synchronize doch erstmal wieder auf den Render- sprich VCL-Thread warten, der dank VSync wartet.
Zitat:
PS: Zu dem Eventproblem. Jedes mal, wenn du Synchronize oder andere Lockings benutzt, erzeugst du eine Situation in der es passieren kann, dass einer warten muss. Und das sollte man so gut wie möglich vermeiden. Außerdem erhöht sich die Chance auf Deadlocks. Das Beste ist da meistens immer es im Thread auszuführen. Aber auch da. Ich kenne die Rahmenbedingungen nicht und es kann sein, dass es für deinen Fall eher nicht praktikabel ist. Muss ja außerdem auch in dein Anwendungsdesign passen.
Das Event war dazu gedacht, die Kräfte noch dynamischer programmierbar zu gestalten (zB. Windablenkung proportional zur Höhe über dem Boden). Da ja der Code ja eigentlich problemlos durchlaufen werden könnte, da er nur mit den ihm übergebenen Parametern arbeitet, die nur zum Rechenthread gehören, nur "im falschen Thread steckt", dachte ich, dass es einen Weg geben müsste, diesen Code auszuführen.
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Also als Erstes zum Leichtesten. Ja du kannst in deinem Falle ein Event benutzen. Wenn du das Event aus dem Execute aufrufst und nur Sachen benutzt die du übergibst ist es vollkommen egal ob dieses Event eine Methode eines Forms ist oder sonst was. Es wird ja aus dem Thread aufgerufen. Ergo ist es ein Teil des Threads. Du darfst nur nicht auf das Form zugreifen.
Mit Partikelsystemen kenne ich mich leider nicht aus. ABER es ist sicher kein schöner Effekt, wenn das Partikelsystem 2 oder 3 Frames überspring, oder? Und das wäre so durchaus möglich. Aber dann hättest du ruckeln wärend des Renderns. Du musst also genau genommen vor jedem Frame immer die Punkte berechnen? Und die müssten dann eigentlich auch alle fertig sein. Korrigiere mich, wenn ich mich irre!
Und das wirft ein etwas anderes Licht auf die Sache. Dann kannst du nämlich mit Events arbeiten. Und zwar wirfst du den Thread an. Und wenn er fertig ist, dann setzt er ein Events. Aus dem VCL Thread bleibt dir dann auch nichts anderes übrig darauf zu warten. Du musst es nur a) entsprechend frühzeitig anwerfen und b) könntest du die 16k Partikel evtl in 4x4k Partikel aufteilen. Dann wären die Ersten 4k schon fertig wärend die 2ten, 3ten und 4ten noch berechnet werden oder werden müssen. Mit der letzten Methode würdest du auf Multi core system richtig was rausholen können, denn das Rendern dauert auch noch.
Ich habe bei meiner Fontbibliothek in dem Archiv mit den Samples eine Multithread Demo. Der "Start" des Threads (die Berechnung) kann genau gesteuert werden. Und der VCL Thread wartet so lange bis die Berechnung abgeschlossen ist. Im zweifel auch eben gar nicht. Allerdings ist die "Arbeit" in dem Beispiel etwas bescheuert, weil ich nicht immer die gleiche Arbeit erledige sondern immer 5ms lang arbeit. Aber der Thread arbeitet parallel zum VCL Thread und das wirklich bei jedem Frame.
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Ahh darum geht es. Ich hatte das Problem auch bei meiner Umsetzung des Partikelsystems. Die Ursache ist vermutlich, dass neue Partikel nicht "rechtzeitig" gespawnt werden, weil die Abstände zwischen den Frames zu groß sind. Das tritt vor allem bei niedrigen FPS und geringen Abständen zwischend den einzelnen Spawns auf. Um das zu lösen, kann man ein Subframe Sampling implementieren.
Das bedeutet, dass man anstatt einmal pro Frame den kram neu zu berechnen, bei jeden Frame in N Subframes aufteilt, wobei N sich aus der vergangenen Zeit und der Zeit zwischen zwei Spawns errechnet. Wenn du jetzt also eine Spawnrate von 10 Partikel pro Sekunde hast und eine halbe Sekunde vergangen ist, musst du deinen Frame in 5 Subframes aufteilen.
Dazu solltest du zu allererst alle bereits vorhandenen Partikel um die genannte halbe Sekunde fortschreiten lassen und eventuell löschen.
Dann baust du dir eine Schleife, in der du die fünf Subframes abklapperst und jedes mal einen Paritkel spawnst und den um T-F*S wobei T die vergangene Zeit, F die nummer des Subframes (beginnend bei 0) und S die zeit zwischen den Subframes ist, fortschreiten lässt.
Das ganze funktioniert wunderbar und in meiner Implementation kostet mich das bei 1k Partikeln keinen merkbaren Frame pro Sekunde. Wenn du willst, kann ich einzelne Stellen später nochmal genauer erläutern, ich habe gerade meinen Code nicht zur hand.
Gruß Lord Horaoznt
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Registriert: Mo Sep 02, 2002 15:41 Beiträge: 867 Wohnort: nahe Stuttgart
Gut, eigentlich hatte ich die Sache mit dem Event doch so erwartet, wollte aber lieber auf Nummer sicher gehen.
Lossy eX hat geschrieben:
Mit Partikelsystemen kenne ich mich leider nicht aus. ABER es ist sicher kein schöner Effekt, wenn das Partikelsystem 2 oder 3 Frames überspring, oder? Und das wäre so durchaus möglich. Aber dann hättest du ruckeln wärend des Renderns. Du musst also genau genommen vor jedem Frame immer die Punkte berechnen? Und die müssten dann eigentlich auch alle fertig sein. Korrigiere mich, wenn ich mich irre!
Du hast insofern Recht, als dass das Partikelsystem für jedes Frame gezeichnet werden soll. Aber dank der CriticalSection wartet der VCL-Thread einfach vor dem Zeichnen kurz bis der Rechenthread mal wieder fertig ist. Der VCL-Thread kann locker mal nen paar ms warten, denn die größte Lockzeit nimmt eh V-Sync in Anspruch. Ansonsten weiß ich nicht, was du mit "Überspringen" meinst.
Wichtig ist, dass der Rechenthread möglichst oft aufgerufen werden kann. Das Problem hat einen mathematischen Ursprung: Ich kann meine derzeit wirkende Kraft/Beschleunigung auf die Partikel dynamisch verändern, vollkommen losgelöst von jeder formell vorhersehbaren Beschreibung. Ich kann aber wiederum meine Partikelgeschwindigkeit und -position nur mit einem (wenn auch relativ kleinen) Zeitabstand berechnen. In diesem Zeitabschnitt aber muss ich meine Beschleunigung und Geschwindigkeit als konstant annehmen. Dadurch kann ich mich dem richtigen Wert nur annähern (vergleichbar mit Ober- und Untersumme von Integralen). Die Näherung wird umso ungenauer, je größer die Zeitschritte werden. Daher wäre mir am liebsten, dass selbige null wären, oder wenigstens so viel null wie nur geht. Eine mögliche Idee wäre auch, die Formel für Kraft/Beschleunigung formell zu beschreiben und im Vorfeld analytisch für Geschwindigkeit und Strecke zu integrieren. Wobei ich fast das Gefühl habe, dass das dann nicht sehr performant wird.
Lord Horazont hat geschrieben:
Ahh darum geht es. Ich hatte das Problem auch bei meiner Umsetzung des Partikelsystems. Die Ursache ist vermutlich, dass neue Partikel nicht "rechtzeitig" gespawnt werden, weil die Abstände zwischen den Frames zu groß sind. Das tritt vor allem bei niedrigen FPS und geringen Abständen zwischend den einzelnen Spawns auf. Um das zu lösen, kann man ein Subframe Sampling implementieren
Stimmt, das könnte durchaus ein Grund sein... zur Zeit versuche ich noch nicht die Position und Geschwindigkeit der neuen Partikel, die "zu spät" erzeugt werden, zu interpolieren. Werde mich mal dran versuchen, wobei hier das gleiche Problem wie oben zum Tragen kommt.
Falls du time based movement verwendest (bei partikeln eher unüblich) kannst du nach dem spawn eines partikels die Move methode ausführen mit random()*DeltaT wobei DeltaT die Zeit zwischen dem letzen und aktuellen frame ist. Das hilft gegen klumpen.
Bei konstanter framerate kannst du statt dessen auch einfach eine Bewegung um random()*speed durchführen. Dann schreiten zwar die anderen Größen nicht voran, bei vielen Partikelsystemen dürfte das jedoch kein Problem sein.
Die Beschleunigung musst du wohl als konstant annehmen, bei der Geschwindigkeit ist das dank Strecke=Geschwindigkeit*DeltaT+0.5*Beschleunigung*DeltaT^2 kein Problem.
Normal arbeitet man bei Partikelsystemen jedoch eher mit geringen Frameraten und einfachen Formeln.
Registriert: Mo Sep 02, 2002 15:41 Beiträge: 867 Wohnort: nahe Stuttgart
Für TBM hat Lord Horazont ja schon "Subframe Sampling" vorgeschlagen. Der Tipp mit der Geschwindigkeit ist gut, die könnte ich wirklich direkt berechnen. Hatte da schon die Vermutung, dass das nicht ganz ideal war.
Nur DeltaT ist bei mir eben nicht die Zeit zwischen den Frames, sondern zwischen den Threadexecutions... das war ja der Witz an der Sache mit variabler Beschleunigung
Aber warum ist es so abwegig, dass sich meine Partikel einfach an die Newtonsche Mechanik halten sollen? Grade durch die variable Beschleunigung kann ich die Bewegungen dann wesentlich dynamischer gestalten.
Die Formeln halte ich eigentlich für nicht zu komplex, da selbst mit ersten Verbesserungen der Rechenthread für 16k Partikel bei mir lediglich 3 ms benötigt, zumal man ihn inzwischen meistens auf einen eigenen Kern schieben kann... und selbst wenn, dann ist das halt mal ein abnormales Partikelsystem.
Ich selber verwende ein SceneGraph, der alle Interessanten Daten enthält(die von meheren Modulen gebraucht werden).
Der Renderer muss nur lesen, die Physik muss lesen und schreiben(animationssystem ist hier auch drin), KI muss lesen und schreiben.
Die Physik muss ja die Positionen von Models ändern(Physik+Pfadlisten) und die KI arbeitet mit den Pfadlisten von Models.
Ein Paralleles arbeiten könnte ich z.B. implementieren, indem die KI die letzte Pfadliste ausliest, dann die änderungen macht(in eine eigene liste) und ein Changed flag setzt.
Ist die Physik dran, dann guckt die nach dem flag, ist es gesetz, dann hol dir von dem Script die veränderte liste und update diese im SG.
Leider braucht die KI auch noch schreibrechte für einiges mehr, vieleicht will es auch mal etwas entfernen(ein model) dann wird es ziemlich ekelig.
Also sollte man KI und Physik sauber syncen.
KI.UpdateData(); --> KI.ExecuteScript(); --> KI wartet oder arbeitet zuende --> KI.UpdateData();
Physik wartet --> Physik.Update(); --> Physik.UpdateData(); --> Physik wartet
wenn schon fertig
UpdateData() ist bei beiden ein Blocking methode, die nach einen access flag im Node geht.
Wird gerade darauf zugegriffen, dann wird gewartet bis man ran darf.
AllowedAccess würde ich das teil nennen und mit 3 states belegen,none(anfang des programms),ki(ki darf jetzt),phy(physik darf jetzt).
Wenn die KI UpdateData() aufruft, dann muss sie warten, bis das Flag ki annimmt.
Die KI schreibt nun die Daten und schreibt in das Flag phy.
Also kann KI nicht schreiben, solange die Physik nicht ihre UpdateData() methode ausgeführt hat und das flag auf ki setzt.
Welcher Prozess anfängt sollte von den Routinen in den jeweiligen Modul abhängig sein.
Ich würde als erstes der Physik den drücker in die Hand geben.
Wenn man ins endlose fällt, dann fällt man und ob ich nun auf die Idee komme mich nach vorne zu bewegen, hat 0 Einfluss auf das Fallen andersrum aber schon.
Wenn ich wirklich mehere Thread nutzen würde, dann wäre allerdings ein Hauptthread Fensterhandling,io und zeichnen,nebenthread Sound,nebenthread Physik und KI.
_________________ "Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren" Benjamin Franklin
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2623 Wohnort: Berlin
Programmiersprache: Go, C/C++
Man kann schon den Speicher schützen, z.B. die pointerklasse überschreiben und dort bei jeden Speicherzugriff ein check auf blockiert machen(globale flagliste erstellen oder pointer so überarbeiten, dass er aus 5 bzw. 9 byte besteht und das byte hinter dem pointer als acess flag dient).
Man muss die entsprechende File im RTL suchen und anpassen und in den Projekteordner legen(damit wird diese immer bevorzugt).
Das Problem wird sein, das pointer wohl nicht im RTL definiert sind, sondern im compilercode.
Für Freepascal kein Problem, da man dort operator overloading hat und die =,+,-,/,* einfach überladen kann.
Da eine system.pas im ordner liegt, wo diese operatorn überladen sind, hat man automatisch für all sein eigenen Code die neuen Operatoren.
Ein bischen C++ Pseudocode:
Code:
Pointer& Pointer::operator = (const Pointer &ptr)
{
if (AccessAllowed(ptr))
*this=ptr;
else
*this=0;
return *this;
}
Das gleiche muss für für die anderen Operatoren auch gemacht werden. Nachteil, wenn nun wer auf die Stelle zugreift, ohne vorher den pointer auf 0 zu prüfen, dann hat man eine tolle access violation. Man kann bei den else zweigen von allen operatoren überladung eine exception werfen, die man selber erstellt hat (AccessDontAllowed=class(Exception); ... raise AccesDontAllowed.Create;). Nun kannst du ja diese Art von Exceptions filtern lassen(siehe ExceptProc:=@KarExceptHandle;), also der Code läuft weiter. Da du ja nur neue Speicherbereiche Blockieren willst, in denen dein Code werkelt, kannst du sogar vorher mit ptr=0 oder try except dein Programmcode dann steuern(als alternative zum exception callback anzapfen).
Code:
try
myvar=verbotenerptr^;
myvar.text="test";
myvar.a=3;
except
end;
Geht, wenn man AccessDontAllowed wirft und die prog beendung durch den exception callback anzapfen(bei allen ausser dieser exception halt;) unterbindet. Da da ne exception kam, wird der restliche Code im block nicht weiter verarbeitet.
Billiger ist es wohl einfach nen kleine Liste global zu erstellen und dort alle ptr, die nicht geschrieben werden sollen reinpackst.
Dann kannst du in deinem code ein If PtrInListr(ptr,mylist) then machen.
Mit viel krativität und arbeit geht sowas immer.
_________________ "Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren" Benjamin Franklin
Registriert: Mo Sep 02, 2002 15:41 Beiträge: 867 Wohnort: nahe Stuttgart
Das hatte ich vor lauter Sachen, die ich so zwischenzeitlich bearbeitet habe, fast vergessen.
Erstmal danke an TAK für soviel interessante Information.
Eben hatte ich die zündende Idee für mein Partikelsystem und ich glaube, das geht in Richtung "asynchron parallel".
Mein derzeitiger Plan sieht so aus:
Ich leite meine Standard-Manager-by-String-Klasse ab und spendiere dieser neben den Partikelsystemdaten dann einen Thread. Der wird dann alle im Manager gespeicherten Systeme nacheinander durchlaufen, sich die Daten kopieren (bei TurboDelphi der zusätzliche Vorteil, sie werden dann auch für SSE aligned), dann den Pointer auf die Daten an ein für jedes Partikelsystem individuell beschreibbares Event übergeben, dann die Daten zurückschreiben.
Für mich macht dieses System soweit Sinn, gibt es Einwände?
Dann noch einige Fragen, die ich mir grade stelle:
1. Soweit ich mitgekommen bin, dürfte bei meinem (neuen) Thread ja eigentlich nichts zu sperren sein, außer wenn er zurückschreibt, oder?
2. Wie arrangieren sich Threads auf Multicore-Systemen? Wechseln sie automatisch zum nächsten Kern, wenn einer beschäftigt ist? Klingt für mich etwas nach Wunschvorstellung, aber vom Zuweisen zu einzelnen Kernen hab ich bislang noch nichts gefunden.
3. Produzieren Threads viel Overhead, sodass es schon problematisch wird, wenn ein paar Threads auf einem Kern laufen? Wenn nein, müsste es ja Sinn machen, möglichst viele große Aufgaben in einen eignen Thread auszulagern (also insgesamt nicht 100, sondern vllt. 5-10 Threads ).
Bei flags musst du sehr aufpassen. Das geht mit normalem Code nicht so einfach (nicht mal wenn das flag als volatile deklariert ist). Da muss man dann spezielle locked Anweisungen verwenden. Also InterlockIncrement und co.
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
WhiteHunter hat geschrieben:
2. Wie arrangieren sich Threads auf Multicore-Systemen? Wechseln sie automatisch zum nächsten Kern, wenn einer beschäftigt ist? Klingt für mich etwas nach Wunschvorstellung, aber vom Zuweisen zu einzelnen Kernen hab ich bislang noch nichts gefunden.
Das ist sache des Betriebssystems. Du kannst aber zumindest unter Windows mit SetThreadAffinityMask (so heißt der Befehl glaube ich) festlegen, auf welchen Prozessoren(kernen) der Thread ausgeführt werden darf. Solltest du aber nicht unbedingt verwenden. Wenn sich das Betriebssystem drum kümmert, sollte es die beste Lösung raussuchen.
WhiteHunter hat geschrieben:
3. Produzieren Threads viel Overhead, sodass es schon problematisch wird, wenn ein paar Threads auf einem Kern laufen? Wenn nein, müsste es ja Sinn machen, möglichst viele große Aufgaben in einen eignen Thread auszulagern (also insgesamt nicht 100, sondern vllt. 5-10 Threads ).
Ich habe irgendwo mal gelesen, dass man nicht mehr als 16 Threads pro Anwendung, am besten aber höchstens 8 oder so haben sollte. Du musst natürlich auch einbeziehen, was für die Synchronisierung der Schreibevents verloren geht. Schließlich dürfen die ja nicht gerade aufgerufen werden, während sich der Renderer alle Daten schnappt.
Gruß Lord Horazont
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2623 Wohnort: Berlin
Programmiersprache: Go, C/C++
Mach die Anzahl der Threads an den Kernen der CPU aus.
Diese Variante hab ich schon bei 1-2 moderneren Programmen gesehen.
Mehr Threads als Kerne zu haben(wo die gleiche routine durchläuft) bringt nichts.
Wenn man 4Kerne hat, 4 Threads für die Partikelberechnung und noch ein paar Threads für andere dinge, dann okey aber 5Threads, für Partikelberechnung, bei 4 Kernen ist murks.
Der 5. Thread braucht noch zeit für das umschalten und holen sowies speichern der register und kommt ja nur dran, wenn die anderen 4 Threads, die das gleiche machen fertig sind.
Es gibt so tolle Crysis Physik Videos, wo man mit dem setzen eines consolenflags die Physikleistung steigert.
Dahinter steckt folgendes, Crysis Physik läuft default auf einem Thread und wenn man das Consolenflag auf 0 setzt, dann werden soviele Threads genutzt wie sinnvoll ist. Ich denke, das hier ebenfalls die Anzahl der Threads auf Kernanzahl gesetzt wird.
_________________ "Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren" Benjamin Franklin
Mitglieder in diesem Forum: 0 Mitglieder und 5 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.