Multithread lock read/write



  • Ähem, dann wäre ich von volatile richtiggehend enttäuscht.
    Oder andersrum gefragt, was hätte volatile für einen Sinn, wenn es nicht voll auf die Targetadresse durchgreift?
    Denn ein anderer Thread kann ja auch nur auf die bekannte Adresse schreiben, woher soll der wissen, daß der andere nur im Cache rumnudelt?

    CPUs sind keine Autisten.
    volatile heißt, guck' nochmal nach, auch wenn der Code sagt, daß man da vorher 2 reingetan hat, schau' nach, ob wirklich 2 drinsteht.
    Und natürlich darf dann das der Compiler nicht wegoptimieren, den Rest macht der Memorycontroller, der bei Inkonsistenz nachlädt.

    Zumindest hab' ich das so verstanden, so genutzt und es hat so funktioniert. 🙂



  • Ja klar heisst volatile "durch bis zum Metall".
    Was volatile nicht heisst/macht:
    * atomic
    * memory ordering



  • olatile heißt, guck' nochmal nach, auch wenn der Code sagt, daß man da vorher 2 reingetan hat, schau' nach, ob wirklich 2 drinsteht.
    Und natürlich darf dann das der Compiler nicht wegoptimieren, den Rest macht der Memorycontroller, der bei Inkonsistenz nachlädt.

    Zumindest hab' ich das so verstanden, so genutzt und es hat so funktioniert.

    stimmt ja auch - nur das eben dadurch trotzdem keine Threadsicherer Zugriff realisiert ist, erstmal nur das überhaupt der Inhalt erreichbar ist - aber nicht ob der auch "im" richtigen Zustand ist



  • und darum schreibe ich auch Lüge oder Mystik - viele missbrauchen volatile als - Threadzugriffssicherung - obwohl es keine ist, es läuft durch pures Glück trotzdem - ist aber einfach total falsch



  • dachschaden schrieb:

    ...

    Hallo,

    sorry das ich mich nicht mehr gemeldet habe.

    Ich habe mir deinen Ansatz nochmal durch den Kopf gehen lassen und ein wenig gegoogled und nun eine stabile Lösung gefunden.

    Ich habe den Thread der mir in der GUI die Werte aktualisiert hat rausgeworfen und lasse das über den Haupthread (=GTK Thread) laufen. Dieser Hauptthread ruft mittels einer Timeout Funktion alle (z.B.) 500ms eine Funktion auf und diese verändert dann die GUI.

    Ein Sensor ist für mich eine Hardware. Jedenfalls läuft dieser wie gehabt in einem eigenen Thread. Beziehungsweise musste ich für jeden Sensor einen eigenen machen, da ich herausgefunden habe, dass das Programm stoppt bis ein neuer Wert angekommen ist. Was zur Folge hätte, das die anderen Sensoren in dieser Wartezeit nichts mehr empfangen hätten.

    Jedenfalls habe ich dann noch meinen Code optimiert, sodass pro Thread nur noch ein einziger Lese/Schreibzugriff auf das Struct nötig ist. Diese Zugriffe habe ich mittels eines Mutex jeweils gelockt.

    Habe mit dieser Lösung keinen speziellen "GTK-Lock" gebraucht, da nur der Hauptthread die GUI updatet.

    Es funktioniert perfekt!

    Danke 🙂



  • JohnDillinger schrieb:

    Es funktioniert perfekt!

    Danke 🙂

    Ich vermute mal, alle Beteiligten hier atmen jetzt tief durch und hoffen dass Dein Temperaturprogramm nicht "systemrelevant" ist - etwa zur Steuerung eines Atomkraftwerks...
    😃



  • JohnDillinger schrieb:

    Ich habe den Thread der mir in der GUI die Werte aktualisiert hat rausgeworfen und lasse das über den Haupthread (=GTK Thread) laufen. Dieser Hauptthread ruft mittels einer Timeout Funktion alle (z.B.) 500ms eine Funktion auf und diese verändert dann die GUI.

    Du wirst es nicht glauben, auf diese Idee bin ich auch gekommen. Allerdings hat dieser Ansatz ein kleines Problem: was, wenn die Hardware hängt? Sprich, Verbindung bricht ab, oder Hardware geht kaputt, und es können keine weiteren Daten geholt werden.

    Ich habe bereits ein Monitoring-Programm geschrieben. Kommt mehr als häufig genug vor, dass eine Verbindung hängen bleibt, und dann geht gar nichts mehr bis zum TCP-Timeout. Und in der Zeit werden dann alle Server und Dienste grün angezeigt, bis es eventuell zu spät ist.

    Wenn in deiner GTK-Anwendung das Werteholen hängt, reagiert die ganze Anwendung nicht mehr. Deswegen lagert man so was in einen externen Thread. Und wenn man mit mehreren Werten arbeitet - nun, kein Problem, ein LWP zu erstellen ist meistens immer noch schneller, als das ganze seriell zu machen. Wie reden hier schließlich von I/O.

    Bei meinem Ansatz kann die Anwendung beispielsweise alle 10s sich selbst prüfen, ob der Thread die Daten ordentlich geschrieben hat. Wenn nicht, wird der Eintrag für den Sensor rot dargestellt.
    Was machst du bei deinem Ansatz?

    JohnDillinger schrieb:

    Ein Sensor ist für mich eine Hardware. Jedenfalls läuft dieser wie gehabt in einem eigenen Thread. Beziehungsweise musste ich für jeden Sensor einen eigenen machen, da ich herausgefunden habe, dass das Programm stoppt bis ein neuer Wert angekommen ist. Was zur Folge hätte, das die anderen Sensoren in dieser Wartezeit nichts mehr empfangen hätten.

    Also - du lässt einen GTK-Timer feuern, der dann, sagen wir mal, 15 Threads erstellt, Werte aus den Sensoren lädt, Fenster aktualisiert, und dann wieder alle 15 Threads joined? Da stellen sich mir doch zwei Fragen:

    - In einem Timer hast du den GTK-Lock bereits, deswegen musst du das nicht selbst machen. Aber eventuell hast du immer noch das Problem, dass 15 Threads gleichzeitig den Status des Fensters ändern wollen. Fängst du das ab? Oder machst du es direkt intelligent und wartest, bis alles gejoint ist, und schreibst dann ordentlich die Werte in das GTK-Fenster?
    - Was ist, wenn ein Thread hängenbleibt, weil die Hardware hängenbliebt? Beim Joinen würde der Timerthread dann einfach ebenfalls hängen. Und die GTK-Anwendung hängt über allem.

    EDIT: @pointercrash():

    Hm. schau dir das mal an

    1. No, volatile doesn't guarantee no caching for this memory location, and there aren't anything about this in C/C++ Standards or compiler manual.
    2. Using memory mapped region, when memory mapped from device memory to CPU-memory is already marked as WC (write combining) instead of WB, that cancels the caching. And need not to do cache-flushing.

    Ist also nicht "runter bis zum Metall" in den meisten Fällen, zumindest verstehe ich das so. Und da, wo es wirklich runter bis zum Metall sein muss, übernimmt die CPU das schon selbst.
    Das scheint aber generell eine Wissenschaft für sich zu sein. Hier eine aufschlussreiche Artikelreihe von Ulrich Drepper.



  • Wenn in deiner GTK-Anwendung das Werteholen hängt, reagiert die ganze Anwendung nicht mehr. Deswegen lagert man so was in einen externen Thread.

    er hat doch einen Thread für das Sensorlesen der die Daten in den Struct schreibt - diese Daten holt er dann per GUI-Timer, so lese ich das



  • abcdefg schrieb:

    JohnDillinger schrieb:

    Es funktioniert perfekt!

    Danke 🙂

    Ich vermute mal, alle Beteiligten hier atmen jetzt tief durch und hoffen dass Dein Temperaturprogramm nicht "systemrelevant" ist - etwa zur Steuerung eines Atomkraftwerks...
    😃

    Isar 1 zurück ans Netz 🙂

    dachschaden schrieb:

    JohnDillinger schrieb:

    Ich habe den Thread der mir in der GUI die Werte aktualisiert hat rausgeworfen und lasse das über den Haupthread (=GTK Thread) laufen. Dieser Hauptthread ruft mittels einer Timeout Funktion alle (z.B.) 500ms eine Funktion auf und diese verändert dann die GUI.

    Du wirst es nicht glauben, auf diese Idee bin ich auch gekommen. Allerdings hat dieser Ansatz ein kleines Problem: was, wenn die Hardware hängt? Sprich, Verbindung bricht ab, oder Hardware geht kaputt, und es können keine weiteren Daten geholt werden.

    Ich habe bereits ein Monitoring-Programm geschrieben. Kommt mehr als häufig genug vor, dass eine Verbindung hängen bleibt, und dann geht gar nichts mehr bis zum TCP-Timeout. Und in der Zeit werden dann alle Server und Dienste grün angezeigt, bis es eventuell zu spät ist.

    Wenn in deiner GTK-Anwendung das Werteholen hängt, reagiert die ganze Anwendung nicht mehr. Deswegen lagert man so was in einen externen Thread. Und wenn man mit mehreren Werten arbeitet - nun, kein Problem, ein LWP zu erstellen ist meistens immer noch schneller, als das ganze seriell zu machen. Wie reden hier schließlich von I/O.

    Bei meinem Ansatz kann die Anwendung beispielsweise alle 10s sich selbst prüfen, ob der Thread die Daten ordentlich geschrieben hat. Wenn nicht, wird der Eintrag für den Sensor rot dargestellt.
    Was machst du bei deinem Ansatz?

    - Also wenn die Hardware hängt, bzw. kein neuer Wert innerhalb einer definierten Zeit reinkommt, bekomme ich das über eine Funktionsabfrage der Schnittstelle mitgeteilt. Das nutze ich auch aktiv, denn ich möchte ebenso dann etwas in rot anzeigen. Der Fall ist somit abgesichert.

    -LWP sagt mir nichts.

    - Wenn sich einer der Threads aufhängt, bekomme ich es nicht mit. Jetzt habe ich noch nicht verstanden, wie du diesen Fall absicherst?

    - Zum Aufhängen des Werteholen: Also wenn sich die Funktion die permanent mit timeout neu aufgerufen wird aufhängt, dann hängt sich alles auf. Aber warum sollte sich jetzt speziell diese Funktion aufhängen? "Weil es immer mal passieren kann", nehme ich an? Ich sags mal so, ist das die gängige Programmierweise, alles so zu 100% abzusichern? Also das Kernkraftwerk hänge ich jetzt nicht dran. Dann müsste ich ja in jeglichen anderen Programmen genauso vorgehen, und jede Funktion in ein thread auslagern, damit sich nicht alles aufhängt wenn sich eine Funktion verabschiedet. Also ich hoffe das ist verständlich was ich meine.
    Muss ich jede Funktion absichern? Es liegt ja nicht an dem Timeout, oder in Verbindung mit den anderen Threads, das diese Funktion besonders "absturzgefährdet" ist? Das soll nicht heissen, das ich den Vorschlag nicht annehmen möchte, das ist jetzt eine Interessensfrage.

    dachschaden schrieb:

    JohnDillinger schrieb:

    Ein Sensor ist für mich eine Hardware. Jedenfalls läuft dieser wie gehabt in einem eigenen Thread. Beziehungsweise musste ich für jeden Sensor einen eigenen machen, da ich herausgefunden habe, dass das Programm stoppt bis ein neuer Wert angekommen ist. Was zur Folge hätte, das die anderen Sensoren in dieser Wartezeit nichts mehr empfangen hätten.

    Also - du lässt einen GTK-Timer feuern, der dann, sagen wir mal, 15 Threads erstellt, Werte aus den Sensoren lädt, Fenster aktualisiert, und dann wieder alle 15 Threads joined? Da stellen sich mir doch zwei Fragen:

    - In einem Timer hast du den GTK-Lock bereits, deswegen musst du das nicht selbst machen. Aber eventuell hast du immer noch das Problem, dass 15 Threads gleichzeitig den Status des Fensters ändern wollen. Fängst du das ab? Oder machst du es direkt intelligent und wartest, bis alles gejoint ist, und schreibst dann ordentlich die Werte in das GTK-Fenster?
    - Was ist, wenn ein Thread hängenbleibt, weil die Hardware hängenbliebt? Beim Joinen würde der Timerthread dann einfach ebenfalls hängen. Und die GTK-Anwendung hängt über allem.

    der GTK Timer erstellt keine Threads.

    Ich erstelle die Threads in der main-Funktion, diese empfangen Daten und knallen sich mithilfe eines Pointers in ein Struct. Der Schreibebefehl wird jeweils durch einen Mutex Lock geschützt. Die Threads laufen permanent.

    Die Timeout-Funktion im Haupt(GTK-)thread holt sich eigenständig die Daten aus diesem Struct (geschützt durch einen Mutex) und nur diese Timeoutfunktion ändert den Status des Fensters. Die anderen Threads haben damit überhaupt nichts am Hut.

    Erübrigt sich damit deine Frage, was passiert wenn ein Thread hängen bleibt?
    Nebenbei wie oben bereits gefragt, wie möchtest du denn so ein Thread hängenbleiben absichern?



  • Gast3 schrieb:

    Wenn in deiner GTK-Anwendung das Werteholen hängt, reagiert die ganze Anwendung nicht mehr. Deswegen lagert man so was in einen externen Thread.

    er hat doch einen Thread für das Sensorlesen der die Daten in den Struct schreibt - diese Daten holt er dann per GUI-Timer, so lese ich das

    genau 👍


Anmelden zum Antworten