Frage Syncronisierung von Thread?



  • jenz schrieb:

    es werden nur ints gelesen bzw. geschrieben.

    was soll da schief gehen?

    da braucht man nichts synchronisieren.

    vielleicht auf irgendwelchen exotischen geräten,
    aber sonst sollte da doch nicht passieren können, oder liege ich da falsch?

    1. Ohne volatile und/oder Mutex ist nichtmal garantiert ob der Compiler für die Zuweisung überhaupt Code generiert.

    2. Ja, auf "exotischen" Geräten (z.B. PowerPC, DEC Alpha, ...) kann es passieren dass Änderungen am Speicher (eben "das Schreiben von ints") die CPU 1 macht von CPU 2 z.B. in der falschen Reihenfolge "gesehen" werden. Was je nachdem um was für Code es sich handelt katastrophale oder garkeine Folgen haben kann.



  • hustbaer schrieb:

    1. Ohne volatile und/oder Mutex ist nichtmal garantiert ob der Compiler für die Zuweisung überhaupt Code generiert.

    da hilft der mutex auch nicht. volatile muss sein.

    hustbaer schrieb:

    1. Ja, auf "exotischen" Geräten (z.B. PowerPC, DEC Alpha, ...) kann es passieren dass Änderungen am Speicher (eben "das Schreiben von ints") die CPU 1 macht von CPU 2 z.B. in der falschen Reihenfolge "gesehen" werden. Was je nachdem um was für Code es sich handelt katastrophale oder garkeine Folgen haben kann.

    was hilft da der mutex?
    da wird doch keine reihenfolge vorgegeben.


  • Mod

    jenz schrieb:

    da hilft der mutex auch nicht. volatile muss sein.

    nein. Bitte mach dich erst mit den Grundlagen ein wenig vertraut. volatile macht zugriffe auf eine variable beobachtbar. Und auch Aufrufe von I/O-Funktionen (zu denen mutex-locks gehören) sind beobachtbar. Folglich sind beide geeignet, "die Generierung von Code zu erzwingen". volatile wiederum ist völlig ungeeignet, die notwendige Semantik für geteilten Zugriff in mehreren Threads auszudrücken, da volatile-Zugriffe nur untereinander und innerhalb eines Threads geordnet sind - alles andere ist im Grunde undefiniert.

    hustbaer schrieb:

    1. Ja, auf "exotischen" Geräten (z.B. PowerPC, DEC Alpha, ...) kann es passieren dass Änderungen am Speicher (eben "das Schreiben von ints") die CPU 1 macht von CPU 2 z.B. in der falschen Reihenfolge "gesehen" werden. Was je nachdem um was für Code es sich handelt katastrophale oder garkeine Folgen haben kann.

    was hilft da der mutex?
    da wird doch keine reihenfolge vorgegeben.

    Ein mutex - so wie andere Synchronisationsprimitive - etabliert eine zeitliche Ordnung von Zugriffen auf denselben (wie das geschieht, kann uns erst mal egal sein) - "vor, während, nach der anforderung des mutex" ist für eine bestmmmte Operation in allen Threads gleich. Da mutex locks, wie oben gesehen, beobachtbar sind und potentiell den globalen Zustand verändern, sind alle Zugriffe auf globale Zustände relativ zu diesem mutex-aufruf geordnet. Damit folgt, dass Datenzugriffe, die durch eine mutex geschützt werden, in allen Threads zeitlich gleich geordnet sind. Und das ist im Grunde, was Synchronisation bedeutet. volatile ist demgegenüber nahezu nutzlos.

    Sichtbarkeit hat mittelbar auch etwas damit zu tun. Hier geht es im Grunde um die Identität von Objekten. Angenommen, wir haben in zwei Therads einen Pointer p auf z.B. ein int und dieser Pointer habe - wie auch immer er erlangt wurde - den gleichen Wert in beiden Threads. Bedeutet das dann, dass *p in beiden Threads auf das gleiche Objekt verweisen?:
    Moderne Prozessoren haben alle einen Cache, der eine Kopie von Inhalten des Hauptspeichers enthält. Operation benutzen im Grunde nur diesen Cache und immer wenn sich dessen Inhalt verändert, muss der Prozessor den entsprechenden Hauptspeicherinhalt anpassen - das geschieht automatisch (und dieser Vorgang ist nebenbei in obigem Sinne zwischen verschiedenen Prozessoren durch die Hardware synchronisiert) ist aber nicht mit der Veränderung des Cacheinhalts identisch. Ein zweiter Prozessor (auf einem anderen Sockel und mit völlig getrennten Cache) muss nun dafür sorgen, dass er seinen Cacheinhalt - sofern dieser eine Kopie des gleichen Speicherplatzes enthält - ebenfalls anpasst. Das ist aber zeitlich und logisch völlig getrennt von der Operation, die die Änderung des Speichers verursacht hat. Für diese Anpassung ist ebenfalls die Hardware zuständig, aber sobald es keinen gemeinsamen Speicherbus mehr gibt (Stichwort NUMA) - oder das Busprotokoll das nicht so her gibt, kann der 2. Prozessor dieses Update nicht mehr zeitgleich mit dem 1. Prozessor durchführen. Beides ist in x86-Systemen weitgehend unproblematisch, da diese Architektur traditionell streng geordnet ist. Das muss nicht so bleiben, zumal eine solche Architektur schlecht skaliert. Was wir hier brauchen, ist eine memory barrier - vereinfacht gesagt synchronisiert diese zwischen Kopien des gleichen Objekts, während einen Mutex (zunächst) nur Zugriffe auf einer Kopie synchronisiert. Ein vollständiger Mutex wird in der Realität natürlich immer auch eine mamemory barrier mitbringen.



  • camper schrieb:

    jenz schrieb:

    da hilft der mutex auch nicht. volatile muss sein.

    nein. Bitte mach dich erst mit den Grundlagen ein wenig vertraut. volatile macht zugriffe auf eine variable beobachtbar. Und auch Aufrufe von I/O-Funktionen (zu denen mutex-locks gehören) sind beobachtbar. Folglich sind beide geeignet, "die Generierung von Code zu erzwingen". volatile wiederum ist völlig ungeeignet, die notwendige Semantik für geteilten Zugriff in mehreren Threads auszudrücken, da volatile-Zugriffe nur untereinander und innerhalb eines Threads geordnet sind - alles andere ist im Grunde undefiniert.

    hustbaer schrieb:

    1. Ja, auf "exotischen" Geräten (z.B. PowerPC, DEC Alpha, ...) kann es passieren dass Änderungen am Speicher (eben "das Schreiben von ints") die CPU 1 macht von CPU 2 z.B. in der falschen Reihenfolge "gesehen" werden. Was je nachdem um was für Code es sich handelt katastrophale oder garkeine Folgen haben kann.

    was hilft da der mutex?
    da wird doch keine reihenfolge vorgegeben.

    Ein mutex - so wie andere Synchronisationsprimitive - etabliert eine zeitliche Ordnung von Zugriffen auf denselben (wie das geschieht, kann uns erst mal egal sein) - "vor, während, nach der anforderung des mutex" ist für eine bestmmmte Operation in allen Threads gleich. Da mutex locks, wie oben gesehen, beobachtbar sind und potentiell den globalen Zustand verändern, sind alle Zugriffe auf globale Zustände relativ zu diesem mutex-aufruf geordnet. Damit folgt, dass Datenzugriffe, die durch eine mutex geschützt werden, in allen Threads zeitlich gleich geordnet sind. Und das ist im Grunde, was Synchronisation bedeutet. volatile ist demgegenüber nahezu nutzlos.

    hallo hallo, vielleicht liest du einfach noch mal den ganzen thread???

    es geht um int variablen, da wird ein mutex überhaupt keine codeerzeugung bewirken...

    und die reihenfolge sehe ich immer noch nicht. klar, mit nem mutex können zwei threads/prozesse nicht gleichzeitig auf die variable zugreifen, aber das können sie bei ints sowieso nicht...
    (edit)
    natürlich prozesse können das, aber es ist völlig egal in dem hier gezeigten beispiel. es gibt keine "reihenfolge"
    (/edit)

    man muss lesen von a und b einfach nicht mit nem lock umgeben.

    wenn ich mehrere schritte nacheinander abarbeiten will, dann muss ich das locken.
    zum beispiel tauschen von zwei variablen:

    pseudo

    lock
    int help = a;
    a = b;
    b = help;
    unlock
    

    aber nur das lesen von dem int???

    gebt mir doch bitte mal ein beispiel...



  • @jenz: Das war eine Allgemeine frage, es können auch andere typen sein... Es ging lediglich darum, ob ich jedes mal lock bzw. unlock bei einem zugriff, oder ob ich die ganze struktur mit den daten komplett locke...


  • Mod

    jenz schrieb:

    hallo hallo, vielleicht liest du einfach noch mal den ganzen thread???

    denkst du nach, bevor du postest?

    man muss lesen von a und b einfach nicht mit nem lock umgeben.
    ...
    wenn ich mehrere schritte nacheinander abarbeiten will, dann muss ich das locken.

    Ohne Begründung ist das nur so dahergesagt. Und nebenbei auch falsch. Selbst wenn der Zugriff als solcher atomar ist, wird das Lesen ohne Synchronisation den Inhalt vor oder nach (bezogen auf die absolute Zeit) der Änderung in einem anderen Thread liefern - das wird selten das sein, was man will.

    BorisDieKlinge schrieb:

    @jenz: Das war eine Allgemeine frage, es können auch andere typen sein... Es ging lediglich darum, ob ich jedes mal lock bzw. unlock bei einem zugriff, oder ob ich die ganze struktur mit den daten komplett locke...

    Beides ist möglich und die Antwort hängt von der Nutzung ab und davon, welche Invarianten zwischen den Elementen der Struktur gelten sollen.



  • camper schrieb:

    jenz schrieb:

    hallo hallo, vielleicht liest du einfach noch mal den ganzen thread???

    denkst du nach, bevor du postest?
    [/quote}

    na klar

    man muss lesen von a und b einfach nicht mit nem lock umgeben.
    ...
    wenn ich mehrere schritte nacheinander abarbeiten will, dann muss ich das locken.

    Ohne Begründung ist das nur so dahergesagt. Und nebenbei auch falsch. Selbst wenn der Zugriff als solcher atomar ist, wird das Lesen ohne Synchronisation den Inhalt vor oder nach (bezogen auf die absolute Zeit) der Änderung in einem anderen Thread liefern - das wird selten das sein, was man will.

    wenn ich einen atomaren zugriff habe, dann hat das nichts mit der reihenfolge zu tun, wie die prozesse/threads darauf zu greifen.
    "bezogen auf die absolute zeit" wird mit den mutexen gar nichts geordnet. außer, dass immer nur einer zugreifen kann, aber nicht in welcher reihenfolge.

    BorisDieKlinge schrieb:

    @jenz: Das war eine Allgemeine frage, es können auch andere typen sein... Es ging lediglich darum, ob ich jedes mal lock bzw. unlock bei einem zugriff, oder ob ich die ganze struktur mit den daten komplett locke...

    Beides ist möglich und die Antwort hängt von der Nutzung ab und davon, welche Invarianten zwischen den Elementen der Struktur gelten sollen.[/quote]
    oh, das habe ich übersehen
    alles was wie ein zugriff aussehen soll, das sollte per mutex gemacht werden.

    verwechsel das nicht mit diesen "reihenfolgen", die hier öfter genannt wurden.
    wenn du möchtest, dass immer thread1 vor thread2 kommt, dann musst du das anders regeln



  • ja klar, dann muss ich die thread über handle events kommunizieren lassen... aber das ist nich notwendig:)


Anmelden zum Antworten