Synchronisierung von Zugriffen auf gemeinsame Daten



  • Super, genau das war die hilfreiche Antwort, auf die ich gehofft hatte Danke @ ~fricky!

    Die Antwort von fricky ist aber leider FALSCH.

    Soll heissen: es gibt auch Systeme wo nichtmal der Zugriff auf "einfache Flags" ohne Synchronisation oder zusätzliche Barriers so funktioniert wie man es sich ganz naiv vorstellen würde. Kann z.B. sein dass Änderungen an dem Flag erst viel später von anderen Threads gesehen werden. Oder auch garnicht. Und natürlich dass Änderungen in der falschen Reihenfolge gesehen werde, und und und...

    Verstehst du jetzt vielleicht etwas besser was ich dir mit meinem 1. Beitrag sagen wollte?

    Es geht gar nicht um die Umsetzung, sondern nur darum, ob überhaupt eine Absicherung nötig ist, um race conditions u. ä. zu vermeiden.

    Dann ist die Antwort, ein ganz klares "ja, immer!".
    Erst wenn du dir ein spezifisches System anguckst kannst du sagen in welchen Fällen man nichts machen muss.

    Und... erst wenn du dir ein spezifisches System anguckst kannst du sagen *welche* Massnahmen an einer bestimmten Stelle nötig sind. Die Frage so allgemein zu stellen macht also IMO keinen Sinn.

    Im konkreten Fall handelt es sich um Variablen mit der selben breite wie die Prozessorarchitektur. Von daher wird der Schreibvorgang selbst atomar durchgeführt

    Wie kommst du auf die Idee dass jede CPU die es gibt Variablen mit "registerbreite" in einem Rutsch lesen/schreiben könnte? Und selbst WENN es nur ein Assembler-Befehl ist, und der Transfer vom/zum Speicher in einem einzigen Schritt gemacht wird - ist immer noch nicht garantiert dass auch alles funktioniert. z.B. wäre es ja schön wenn andere CPUs auch was von der Änderung mitbekommen, und möglichst auch gleich, nicht erst irgendwann. Was aber nicht garantiert ist.



  • hustbaer schrieb:

    Kann z.B. sein dass Änderungen an dem Flag erst viel später von anderen Threads gesehen werden. Oder auch garnicht

    das solltest du mal genauer erklären. vor allem das 'garnicht'. aber unter berücksichtigung, dass der OP seine variable 'volatile' deklariert hat (siehe erstes posting).
    🙂



  • ~fricky schrieb:

    hustbaer schrieb:

    Kann z.B. sein dass Änderungen an dem Flag erst viel später von anderen Threads gesehen werden. Oder auch garnicht

    das solltest du mal genauer erklären. vor allem das 'garnicht'. aber unter berücksichtigung, dass der OP seine variable 'volatile' deklariert hat (siehe erstes posting).
    🙂

    volatile hat nicht viel mit synchronisation zu tun, es sagt dem compiler lediglich dass etwas nicht im register gelagert werden darf. hast du z.b. einen zweiten prozessor der garnichts vom cache des ersten prozessors weiss, hast du schon verloren. aber das passiert dir vermutlich nicht bei einer x86 architektur, wenn du unter windows auf anwendungsseite programmierst.

    auf anderen systemen kann es eventuell sein dass du explizit die cpu pipeline flushen musst, den cache ebenfalls flushen oder sogar direkt am cache vorbeischreiben musst. aber da sollte man dann nicht mehr im forum fragen, sondern sich die paper der architektur durchlesen.



  • rapso schrieb:

    volatile hat nicht viel mit synchronisation zu tun, es sagt dem compiler lediglich dass etwas nicht im register gelagert werden darf.

    teilweise richtig. 'volatile' sagt einem standardkonformen c-compiler, dass auf jeden fall das 'physikalische objekt', also die speicherzelle bzw. der i/o-ports bei schreib- und lesezugriffen angesprochen werden muss. wenn auf einem multiprozessor-system ein cache-flush dazu gehört, dann muss auch der gemacht werden. mit synchronisation hat es zwar direkt nichts zu tun, aber 'volatile' sorgt zumindest dafür, dass änderungen des speichers für mehrere tasks bzw. mehrere prozessoren zeitnah sichtbar sind.
    siehe auch: http://www.open-std.org/JTC1/SC22/wg14/www/docs/n897.pdf
    🙂



  • ~fricky schrieb:

    hustbaer schrieb:

    Kann z.B. sein dass Änderungen an dem Flag erst viel später von anderen Threads gesehen werden. Oder auch garnicht

    das solltest du mal genauer erklären. vor allem das 'garnicht'. aber unter berücksichtigung, dass der OP seine variable 'volatile' deklariert hat (siehe erstes posting).
    🙂

    Nö, ich hab das schon so oft erklärt.

    Lies doch einfach mal ein paar Artikel im Netz zu dem Thema, oder irgendwelche Papers.
    Tip: es gibt Caches, und nicht alle CPUs halten die ohne Barriers/Fences/... so schön kohärent wie die x86 Familie.

    teilweise richtig. 'volatile' sagt einem standardkonformen c-compiler, dass auf jeden fall das 'physikalische objekt', also die speicherzelle bzw. der i/o-ports bei schreib- und lesezugriffen angesprochen werden muss. wenn auf einem multiprozessor-system ein cache-flush dazu gehört, dann muss auch der gemacht werden.

    Rofl. Träum weiter. Und lies mal bitte den C++ Standard, der (C++ Standard) wird sich nämlich ordentlich wundern wenn du ihm das erzählst.

    mit synchronisation hat es zwar direkt nichts zu tun, aber 'volatile' sorgt zumindest dafür, dass änderungen des speichers für mehrere tasks bzw. mehrere prozessoren zeitnah sichtbar sind.

    Falsch.

    siehe auch: http://www.open-std.org/JTC1/SC22/wg14/www/docs/n897.pdf

    Und?

    1. das ist C99 und nicht C++. Sprache wurde keine genannt, also gehe ich davon aus dass es vielleicht C++ sein könnte.

    2. Der OP hat gesagt es geht ihm "nicht um eine spezifische Umsetzung für Windows/Posix oder was auch immer", also auch nicht um eine in Java oder speziellen Systemen die im Gegensatz zu C99 oder C++ ein Speichermodell vorschreiben welches sowas wie Threads überhaupt kennt.
      Oder nochmal einfach: ohne ein "System" oder eine "Plattform" die definiert was "volatile" bedeutet hat "volatile" genau garkeine Bedeutung.

    3. Siehe (2): C99 und/oder C++ schreiben bezüglich volatile nichts vor was mit Threads irgendwie in Zusammenhang stehen würde. Ein Speichermodell mit Regeln für Multithreading ist für den neuen C++ Standard geplant, entsprechende Papers lassen sich ohne grossen Aufwand im Netz finden.



  • hustbaer schrieb:

    1. Siehe (2): C99 und/oder C++ schreiben bezüglich volatile nichts vor was mit Threads irgendwie in Zusammenhang stehen würde.

    das stimmt zwar, sie schreiben aber vor, dass eine 'volatile' variable nicht gecached werden darf. aus dem von mir geposteten link: A volatile object is also an appropriate model for a variable shared among multiple processes.

    hustbaer schrieb:

    Oder nochmal einfach: ohne ein "System" oder eine "Plattform"
    die definiert was "volatile" bedeutet hat "volatile" genau garkeine Bedeutung.

    was 'volatile' bedeutet, deiniert z.b. der C-standard, nicht das system. auf systemen, die sowieso nichts cachen, ist sowas wie 'volatile' natürlich überflüssig.
    🙂



  • ~fricky schrieb:

    rapso schrieb:

    volatile hat nicht viel mit synchronisation zu tun, es sagt dem compiler lediglich dass etwas nicht im register gelagert werden darf.

    teilweise richtig. 'volatile' sagt einem standardkonformen c-compiler, dass auf jeden fall das 'physikalische objekt', also die speicherzelle bzw. der i/o-ports bei schreib- und lesezugriffen angesprochen werden muss. wenn auf einem multiprozessor-system ein cache-flush dazu gehört, dann muss auch der gemacht werden.

    nein, das ist nicht was es bedeutet. ein compiler muss sich nicht darum kuemmert dass flushes gemacht werden oder am cache vorbei geschrieben wird.

    deiner definition nach wuerde kein compiler der welt je standard conform werden koennen, weil keiner zur laufzeit des schlussendlichen binaries anhand der addresse wissen koennte wie er sich plattformspecifisch korrekt verhalten sollte.

    mit synchronisation hat es zwar direkt nichts zu tun, aber 'volatile' sorgt zumindest dafür, dass änderungen des speichers für mehrere tasks bzw. mehrere prozessoren zeitnah sichtbar sind.
    siehe auch: http://www.open-std.org/JTC1/SC22/wg14/www/docs/n897.pdf
    🙂

    nein, macht volatile nicht. lies dir dein pdf selbst genauer durch, volatile sorgt lediglich dafuer dass der compiler die variable nicht im register behaelt, sondern explizit immer zurueckschreibt bzw ausliest.

    im falle von

    static volatile int32_t test=1;
    .
    .
    .
    void funktion()
    {
    while(test)
    {
    }
    

    wird dir ein compiler ohne volatile einfach eine endlosschleife generieren, das selbe gilt fuers schreiben, beim schreiben innerhalb der schleife, ohne test zu nutzen, wuerde er test nach der schleife erst aus dem register schreiben. mit volatile weist er den wert immer zu.
    fuer ein pipeline flush auf simplen powerpc musst du dann noch __asm__ volatile("sync"); explizit angeben, danach eventuell das OS anweisen den cache zu flushen. auf mips musst du am cache vorbei schreiben indem du das oberste bit der addresse setzt. ... du bist ebenfalls dafuer verantwortlich, dass alles in der richtigen reihenfolge geschrieben wird, hast du mehrere variablen die in den speicher sollten, darfst du dich nicht drauf verlassen dass der compiler bzw die architektur sie in der im c source angegebenen reihenfolge machen, du musst das explizit sicherstellen, falls die reihenfolge wichtig ist, z.b. wenn du einen commandbuffer befuellst und dann den cmdb-pointer weiterschiebst.



  • rapso schrieb:

    nein, das ist nicht was es bedeutet. ein compiler muss sich nicht darum kuemmert dass flushes gemacht werden oder am cache vorbei geschrieben wird.

    deiner definition nach wuerde kein compiler der welt je standard conform werden koennen, weil keiner zur laufzeit des schlussendlichen binaries anhand der addresse wissen koennte wie er sich plattformspecifisch korrekt verhalten sollte.

    Häh? Wozu brauche ich dann einen Compiler und 'volatile'? Der Compiler muß sich merken, ab wo es volatile ist und zur Runtime (falls Parameter weitergereicht werden) den Ursprung konsistent auflösen.

    rapso schrieb:

    im falle von

    static volatile int32_t test=1;
    .
    .
    .
    void funktion()
    {
    while(test)
    {
    }
    

    wird dir ein compiler ohne volatile einfach eine endlosschleife generieren, das selbe gilt fuers schreiben, beim schreiben innerhalb der schleife, ohne test zu nutzen, wuerde er test nach der schleife erst aus dem register schreiben. mit volatile weist er den wert immer zu.

    Ich suche noch die Pointe ... ohne volatile persistentes static, Endlosschleife, ja klar. Ab

    if (test) test = 0;
    

    in dem while()- Block muß er test holen, auswerten und zurückschreiben. Nix Endlosschleife. 🤡
    Aber eigentlich ist static volatile für Hardware gedacht, so daß sich test irgendwann von Außen ändern wird:

    A static volatile object is an appropriate model for a memory-mapped I/O register. Implementors of C translators should take into account relevant hardware details on the target systems when implementing accesses to volatile objects.

    ^^^^^^^^^^^^ (s.o. PDF)

    rapso schrieb:

    fuer ein pipeline flush auf simplen powerpc musst du dann noch __asm__ volatile("sync"); explizit angeben,

    Nöh. Das müssen meine Compiler brav machen, sonst nicht Standard und auf OS zurechtkastriert und ab in die Mülltonne. 👎

    rapso schrieb:

    danach eventuell das OS anweisen den cache zu flushen.

    Hat mit volatile nicht soviel zu tun, wenn das OS aus Geschwindigkeitsgründen Inkonsistenzen riskiert. -> API

    rapso schrieb:

    auf mips musst du am cache vorbei schreiben indem du das oberste bit der addresse setzt. ... du bist ebenfalls dafuer verantwortlich, dass alles in der richtigen reihenfolge geschrieben wird, hast du mehrere variablen die in den speicher sollten, darfst du dich nicht drauf verlassen dass der compiler bzw die architektur sie in der im c source angegebenen reihenfolge machen, du musst das explizit sicherstellen, falls die reihenfolge wichtig ist, z.b. wenn du einen commandbuffer befuellst und dann den cmdb-pointer weiterschiebst.

    Wenn ich einen nackigen Prozessor und 'nen C- Compiler habe, verlasse ich mich primär darauf, daß das so sequentiell wie in der Source abläuft mit entsprechender Vorsicht bei Hardwarezugriffen, die durch static volatile impliziert sind (jaja, die Precautions, die langen, die kruden).
    Sonst könnte man ja gar nichts Deterministisches bauen. 😉



  • Hallo,

    also erst einmal danke für euren geballten Eifer 🙂

    Ich muss das ganz doch etwas präzisieren: Die Sprache ist C, es handelt sich um ein Einprozessorsystem und Variablen, die entweder global sind oder auch nur einmal existieren, aber über Zeiger weitergereicht werden.

    Meine Aussage bzgl. Atomarität war dann zu pauschal, was ich gemeint hatte war folgendes: Von dem verwendeten Compiler wird Assemblercode erzeugt, der neue Werte in einem Befehl schreibt (bzw. liest). Also kann höchstens ein veralteter Wert verwendet werden, in keinem Fall eine Mischung aus altem/neuen Low/High Nibble oder so.

    Von daher denke ich, dass auf der beschriebenen Plattform keine Synchronisation nötig ist. Stimmt das so?

    Zur zweiten Frage nochmal: Weiß jemand, ob bzw. wie Regler mit unterschiedlichen Abtastperioden normalerweise synchronisiert werden - man müsste ja für eine Synchronisierung im schnelleren Regler immer mitzählen, wieviele Perioden schon vergangen sind. Oder evtl. nen zählenden Semaphor verwenden.



  • rapso schrieb:

    ein compiler muss sich nicht darum kuemmert dass flushes gemacht werden oder am cache vorbei geschrieben wird.

    richtig, er muss sich nur darum kümmern, dass echte physikalische schreib/lese-zugriffe auf ein objekt stattfinden, bevor der code hinter dem nächsten sequenzpunkt ausgeführt wird, wenn das objekt als 'volatile' deklariert wurde. wie er das macht, bleibt ihm überlassen.

    rapso schrieb:

    deiner definition nach wuerde kein compiler der welt je standard conform werden koennen, weil keiner zur laufzeit des schlussendlichen binaries anhand der addresse wissen koennte wie er sich plattformspecifisch korrekt verhalten sollte.

    das ist nicht meine definition, sondern die der c-standard-schreiberlinge. und wenn eine rechnerarchitektur das nicht zulässt, dann kann es für diesen rechner leider keinen compiler geben, der 'volatile' standardkonform unterstützt.

    synchronisator schrieb:

    Meine Aussage bzgl. Atomarität war dann zu pauschal, was ich gemeint hatte war folgendes: Von dem verwendeten Compiler wird Assemblercode erzeugt, der neue Werte in einem Befehl schreibt (bzw. liest). Also kann höchstens ein veralteter Wert verwendet werden, in keinem Fall eine Mischung aus altem/neuen Low/High Nibble oder so.
    Von daher denke ich, dass auf der beschriebenen Plattform keine Synchronisation nötig ist. Stimmt das so?

    das kommt drauf an. in der regel tickert in solchen multitasking-systemen ein timer-interrupt, der's dem scheduler erlaubt, zwischen den tasks periodisch hin- und herzuschalten. ein interrupt kann normalerweise keinen angefangenen maschinenbefehl unterbrechen, sondern schlägt immer vorher oder hinterher zu. d.h. wenn bei dir z.b. 16-bit zugriffe in einem rutsch passieren und ein solcher mit einem maschinenbefehl gemacht wird, dann geht es. was aber sein kann ist z.b. dass der compiler einen vermeintlich 16-bittigen zugriff doch in 2 8-bit zugrffe zerlegt, weil die variable an einer ungeraden adresse beginnt und die cpu keine 16-bit zugriffe auf ungerade adressen machen kann. da musste mal in die doku deines systems und compilers gucken, um mehr rauszufinden.
    🙂



  • ~fricky schrieb:

    rapso schrieb:

    ein compiler muss sich nicht darum kuemmert dass flushes gemacht werden oder am cache vorbei geschrieben wird.

    richtig, er muss sich nur darum kümmern, dass echte physikalische schreib/lese-zugriffe auf ein objekt stattfinden, bevor der code hinter dem nächsten sequenzpunkt ausgeführt wird, wenn das objekt als 'volatile' deklariert wurde. wie er das macht, bleibt ihm überlassen.

    'echte' ist eine schwammige behauptung von dir.
    genau gesagt, ich wiederhole mich gerne, darf er den wert nicht nur im register behalten. ob dieser schreibvorgang 'echt' im physikalischem speicher ankommt ist nicht mehr sache des compilers.

    rapso schrieb:

    deiner definition nach wuerde kein compiler der welt je standard conform werden koennen, weil keiner zur laufzeit des schlussendlichen binaries anhand der addresse wissen koennte wie er sich plattformspecifisch korrekt verhalten sollte.

    das ist nicht meine definition, sondern die der c-standard-schreiberlinge. und wenn eine rechnerarchitektur das nicht zulässt, dann kann es für diesen rechner leider keinen compiler geben, der 'volatile' standardkonform unterstützt.

    das ist deine interpretation davon, wenn das so waere, braeuchte man keine fences (und die gibt es selbst auf x86.



  • Auch ein interessanter Einwand. Laut Datenblatt der CPU werden solche Zugriffe durch die Speicherschnittstelle entsprechend verschoben. Von daher passt wohl alles 🙂



  • rapso schrieb:

    das ist deine interpretation davon, wenn das so waere, braeuchte man keine fences (und die gibt es selbst auf x86.

    aber 'fences' beissen sich doch nicht mit dem, was ich hier erzähle. 'volatile' sorgt dafür, dass zugriffe auch tatsächlich stattfinden und der zugriff bei beginn der nächsten anweisung (in derselben task) vollständig abgeschlossen ist. in welcher zeitlichen reihenfolge andere tasks diese zugriffe wahrnehmen (weil z.b. die hardware buszugriffe optimiert), wird nicht durch volatile geregelt. darüber steht nichts im C-standard (und im entsprechenden dokument von C's fettleibiger schwester sicherlich auch nicht). was aber volatile (als logische konsequenz) sicherstellt ist, dass änderungen eines volatile-objekts in anderen tasks sichtbar sind, weil beide auf dieses zielobjekt auch wirklich zugreifen müssen.
    🙂



  • synchronisator schrieb:

    Ich muss das ganz doch etwas präzisieren: Die Sprache ist C, es handelt sich um ein Einprozessorsystem und Variablen, die entweder global sind oder auch nur einmal existieren, aber über Zeiger weitergereicht werden.

    Das ist ungünstig, weil Du nur zur Compiletime "volatile" aufgelöst bekommst.

    synchronisator schrieb:

    Also kann höchstens ein veralteter Wert verwendet werden, in keinem Fall eine Mischung aus altem/neuen Low/High Nibble oder so.

    Die Frage ist, wie portabel das werden soll. Mach 'ne Note rein oder eine ordentliche Doppelabfrage.

    synchronisator schrieb:

    Von daher denke ich, dass auf der beschriebenen Plattform keine Synchronisation nötig ist. Stimmt das so?

    Der geschilderte 2- Thread Mechanismus klingt sauber soweit.

    synchronisator schrieb:

    Zur zweiten Frage nochmal: Weiß jemand, ob bzw. wie Regler mit unterschiedlichen Abtastperioden normalerweise synchronisiert werden - man müsste ja für eine Synchronisierung im schnelleren Regler immer mitzählen, wieviele Perioden schon vergangen sind. Oder evtl. nen zählenden Semaphor verwenden.

    Ei, ei, ei, richtig, isochrone Algorithmen und Multitasking vertragen sich eigentlich nicht, ich denke, Du solltest mehr in medias res gehen - also, was genau brauchst Du?



  • ~fricky, du misverstehst da eine sache, und zwar gröber: volatile kümmert sich (in C und C++) nur um dinge die der compiler selbst macht. volatile sorgt also dafür dass der compiler nicht selbst einen wert in einem register behält oder verspätet zurückschreibt, weil er weiss dass der wert kurz später sowieso nochmal geschrieben wird.

    volatile ist also auch NICHT ohne auswirkungen auf systemen die keinen cache haben. überflüssig ist es sowieso zu 100%, aber das ist wieder eine andere geschichte.

    was caches, reordering in der CPU etc. angeht: darüber sagt der C++ standard nichts aus, und es gibt auch kaum compiler die dahingehend irgendwas machen wenn man "volatile" verwendet. MSVC ab version 8 oder 9 gibt da gewisse garantien, aber das ist so ziemlich der einzige C++ compiler. GCC macht genau nichts in der richtung.

    volatile stellt also auch NICHT sicher dass eine änderung von thread A irgendwann von thread B gesehen wird. warum? eben weil es CPUs gibt die ihre caches nicht selbst synchronisieren, und volatile auf dieser ebene nichts bewirkt.

    ----

    wenn du volatile mit der bedeutung möchtest die du hier unterstellst, dann musst du entweder java programmieren, oder auf den neuen C++ standard warten, in dem das hoffentlich endlich geregelt wird.



  • hustbaer schrieb:

    überflüssig ist es sowieso zu 100%, aber das ist wieder eine andere geschichte.

    nun mach's nicht so spannend. wieso ist 'volatile', nach deiner meinung, zu 100% überflüssig?
    🙂



  • das würd mich auch mal interessieren lol



  • pointercrash() schrieb:

    rapso schrieb:

    nein, das ist nicht was es bedeutet. ein compiler muss sich nicht darum kuemmert dass flushes gemacht werden oder am cache vorbei geschrieben wird.

    deiner definition nach wuerde kein compiler der welt je standard conform werden koennen, weil keiner zur laufzeit des schlussendlichen binaries anhand der addresse wissen koennte wie er sich plattformspecifisch korrekt verhalten sollte.

    Häh? Wozu brauche ich dann einen Compiler und 'volatile'?

    damit er es nicht im register haellt.

    Der Compiler muß sich merken, ab wo es volatile ist und zur Runtime (falls Parameter weitergereicht werden) den Ursprung konsistent auflösen.

    ein compiler kann nicht ueber alle systeme bescheid wissen, wenn deine graphikkarte ne variable liest und dein compiler sie einfach nur in den speicher schreibt, wird die graka diese variable nie sehen weil sie nur im cache bleibt (falls die architektur den wert nicht ab und zu rausschreibt). passiert z.b. auf gamecube und anderen powerpc architekturen.

    egal ob mit oder ohne volatile.

    rapso schrieb:

    im falle von

    static volatile int32_t test=1;
    .
    .
    .
    void funktion()
    {
    while(test)
    {
    }
    

    wird dir ein compiler ohne volatile einfach eine endlosschleife generieren, das selbe gilt fuers schreiben, beim schreiben innerhalb der schleife, ohne test zu nutzen, wuerde er test nach der schleife erst aus dem register schreiben. mit volatile weist er den wert immer zu.

    Ich suche noch die Pointe ... ohne volatile persistentes static, Endlosschleife, ja klar. Ab

    if (test) test = 0;
    

    in dem while()- Block muß er test holen, auswerten und zurückschreiben. Nix Endlosschleife. 🤡

    dafuer andere schweinereien, was wenn thread 1 sich test holt und an if vorbei kommt und bevor er test auf 0 setzt, kommt thread 2 dran und kommt auch an test vorbei, dann hast du ploetzlich zwei threads die da lang laufen. je nachdem was danach gemacht wird, kann ziemlicher misst rauskommen.

    Aber eigentlich ist static volatile für Hardware gedacht, so daß sich test irgendwann von Außen ändern wird:

    A static volatile object is an appropriate model for a memory-mapped I/O register. Implementors of C translators should take into account relevant hardware details on the target systems when implementing accesses to volatile objects.

    ^^^^^^^^^^^^ (s.o. PDF)

    das heisst lediglich, dass ein IO register bei dir IO gemappt wird. wenn du einen cmdbuffer implementierst der mit einer anderen hardware zusammenarbeitet und du weist dieser hardware diesen speicherbereich dafuer zu, kann der compiler nichts machen.
    ebenfalls wenn du einfach nur daten in gecachten bereich schreiben willst der auf einer anderen hardware liegt. es liegt durchaus im interesse des users dass nicht bei jedem byte zugriff die cacheline rausgeschrieben wird. etc etc.

    rapso schrieb:

    fuer ein pipeline flush auf simplen powerpc musst du dann noch __asm__ volatile("sync"); explizit angeben,

    Nöh. Das müssen meine Compiler brav machen, sonst nicht Standard und auf OS zurechtkastriert und ab in die Mülltonne. 👎

    da das ein compiler nicht wissen kann, macht er das nicht. ich weiss nicht woher du diese unsinnige behauptung hast. ich muss das bei VC++, gcc 4.1 und IBM selbst machen, der compiler hat 0 ahnung wann er das machen sollte. natuerlich koennte er das immer machen, aber da so ein sync 20 bis 600 cycle kosten kann, waere es nicht im sinne des erfinders.

    rapso schrieb:

    danach eventuell das OS anweisen den cache zu flushen.

    Hat mit volatile nicht soviel zu tun,

    eigentlich schon, ohne volatile waere ein flush eventuell sinnlos da der compiler den wert im register behalten koennte. deswegen, erst volatile zuweisen, dann sync bzw flush.

    rapso schrieb:

    auf mips musst du am cache vorbei schreiben indem du das oberste bit der addresse setzt. ... du bist ebenfalls dafuer verantwortlich, dass alles in der richtigen reihenfolge geschrieben wird, hast du mehrere variablen die in den speicher sollten, darfst du dich nicht drauf verlassen dass der compiler bzw die architektur sie in der im c source angegebenen reihenfolge machen, du musst das explizit sicherstellen, falls die reihenfolge wichtig ist, z.b. wenn du einen commandbuffer befuellst und dann den cmdb-pointer weiterschiebst.

    Wenn ich einen nackigen Prozessor und 'nen C- Compiler habe, verlasse ich mich primär darauf, daß das so sequentiell wie in der Source abläuft mit entsprechender Vorsicht bei Hardwarezugriffen, die durch static volatile impliziert sind (jaja, die Precautions, die langen, die kruden).
    Sonst könnte man ja gar nichts Deterministisches bauen. 😉

    ja, wenn man sich wenig auskennt verlaesst man sich drauf. ich hab damit taeglich zu tun und ich weiss, dass jede hardware ihre eigenen spezialitaeten hat. leute die sich nicht auskennen vertrauen einfach darauf das es immer so laufen wird wie bei 10tests und checken das ein. andere knallen an jeder moeglichen stelle nen mutex rein vor panik und haben unmengen synchronisationsaufwand der mehr kostet als threads bringen.
    ich weiss dass compiler dir keine grossartigen syncs einbauen, aus diesem grund gibt es explizit befehle und addressmasken um dennoch zum ziel zu kommen. hast du code wie

    struct
    {
    volatile int foo;
    volatile int bar;
    };
    ..
    volatile int array[...];
    

    und greifst du darauf in der folge zu

    foo=1;
    array[x]=..;
    bar=1;
    

    kann dir die hardware diese schreibzugriffe umordnen in

    foor=1;
    bar=1;
    array[x]=....;
    

    weil es von den cachelines her guenstiger ist. willst du das verhindern, brauchst du einen sync/fence/data barrier.

    sorry fuer die spaete antwort 😉



  • rapso schrieb:

    ein compiler kann nicht ueber alle systeme bescheid wissen, wenn deine graphikkarte ne variable liest...

    über angeschlossene zusatzhardware weiss er natürlich nix, aber sonst weiss er sehr wohl eine menge über die hardware, für die er entwickelt wurde. z.b. der IAR für ARM-basierte controller kennt ca 300 verschiedene target-devices. wieso wohl? deiner ansicht nach würde es doch reichen, wenn er bloss ARM7...ARM11 code generieren könnte, ohne jegliches wissen über die komponenten und internen bussysteme der controller.

    rapso schrieb:

    rapso schrieb:

    fuer ein pipeline flush auf simplen powerpc musst du dann noch __asm__ volatile("sync"); explizit angeben,

    Nöh. Das müssen meine Compiler brav machen, sonst nicht Standard und auf OS zurechtkastriert und ab in die Mülltonne. 👎

    da das ein compiler nicht wissen kann, macht er das nicht.

    ein guter compiler sollte mehr mehr wissen, als nur wie maschinencode für den cpu-core erzeugt wird. sonst kannst du auch gleich gcc nehmen.
    🙂



  • ~fricky schrieb:

    rapso schrieb:

    ein compiler kann nicht ueber alle systeme bescheid wissen, wenn deine graphikkarte ne variable liest...

    über angeschlossene zusatzhardware weiss er natürlich nix, aber sonst weiss er sehr wohl eine menge über die hardware, für die er entwickelt wurde. z.b. der IAR für ARM-basierte controller kennt ca 300 verschiedene target-devices. wieso wohl?

    weil es unglaublich viele inkarnationen von ARM cores gibt. jeder hersteller mit lizens kann sich seine persoenliche cpu zusammenstecken. die sind nicht zwingend untereinander kompatibel und haben andere performanceeigenschaften beim optimieren. (also der selbe grund weshalb intel und MS verschiede cpu profile trotz compatibilitaet unterstuetzen).

    deiner ansicht nach würde es doch reichen, wenn er bloss ARM7...ARM11 code generieren könnte, ohne jegliches wissen über die komponenten und internen bussysteme der controller.

    rapso schrieb:

    rapso schrieb:

    fuer ein pipeline flush auf simplen powerpc musst du dann noch __asm__ volatile("sync"); explizit angeben,

    Nöh. Das müssen meine Compiler brav machen, sonst nicht Standard und auf OS zurechtkastriert und ab in die Mülltonne. 👎

    da das ein compiler nicht wissen kann, macht er das nicht.

    ein guter compiler sollte mehr mehr wissen, als nur wie maschinencode für den cpu-core erzeugt wird. sonst kannst du auch gleich gcc nehmen.
    🙂

    und nochmals, das hat nichts mit der guete des compilers zu tun. es reicht schon der unterschied zwischen single socket systemen und multisocket und schon verhaelt sich die synchronisation anders, der compiler kann unmoeglich wissen welche hardware du alles nutzt und wird keine systemcalls implizit einbauen um fuer dich zu synchronisieren.
    ansonsten sag mir bitte einfach wie ein compiler wissen kann, ob ein schreibzugriff auf einen speicherbereich einen flush des caches braucht, oder soll jeder volatile write mehrere kiloCycles kosten?


Anmelden zum Antworten