Frage Syncronisierung von Thread?



  • ahh genau, das wollte ich wissen... dacht evtl. das ofte lockereich auf die performce geht



  • BorisDieKlinge schrieb:

    ahh genau, das wollte ich wissen... dacht evtl. das ofte lockereich auf die performce geht

    das kann auch passieren, wenn sich hinter den locks/unlocks funktionen verbergen, deren laufzeit man nicht vernachlässigen darf. musste eben messen, was besser ist in deinem fall.



  • hmm ok.. wie siehts bei std::list<> aus? Wenn ein thread bsp. das vordeste element löscht, und ein andere mitten in der liste am iterieren ist? Bei nem std::vector wird problematischer sein



  • Apeman schrieb:

    BorisDieKlinge schrieb:

    ahh genau, das wollte ich wissen... dacht evtl. das ofte lockereich auf die performce geht

    das kann auch passieren, wenn sich hinter den locks/unlocks funktionen verbergen, deren laufzeit man nicht vernachlässigen darf. musste eben messen, was besser ist in deinem fall.

    lol
    WENN sich hinter lock/unlock Funktionen verbergen deren Laufzeit man nicht vernachlässigen darf. Muahaha. WANN ist das denn nicht so bitte?
    Locks sind *immer* langsam.
    Die Bandbreite erstreckt sich dabei bloss von "langsam" bis "ganz furchtbar schweine-langsam".



  • hustbaer schrieb:

    Locks sind *immer* langsam.

    wieso? bist du winapi-coder?

    #define LOCK() scheduler_ticks &= ~ON; while(pending_tasks);
    #define UNLOCK() scheduler_ticks |= ON;
    

    😉
    ausserdem kommt's ja noch auf die aufruffrequenz der locks und unlocks an.
    in der regel ist es in muktitasking-systemen besser, wenn eine resource oder critical section schnell wieder frei wird.



  • In der WinAPI gibt's afair auch atomare Int-Operationen. Das heißt, Du kommst ganz ohne Locks und Mutexes aus.



  • Jester schrieb:

    In der WinAPI gibt's afair auch atomare Int-Operationen. Das heißt, Du kommst ganz ohne Locks und Mutexes aus.

    stimmt: http://msdn2.microsoft.com/en-us/library/ms683590.aspx



  • naja ich verwende das winapi critical_section gedöns... ist das so langsam? wie gehts schneller in der puren c++ syncronisierung?

    #define LOCK() scheduler_ticks &= ~ON; while(pending_tasks);
    #define UNLOCK() scheduler_ticks |= ON;
    

    scheduler_ticks, pending_tasks und ON ?? was sind das für funktionen, kann mir das mal jemand erklären?



  • BorisDieKlinge schrieb:

    scheduler_ticks, pending_tasks und ON ?? was sind das für funktionen, kann mir das mal jemand erklären?

    das ist nur pseudocode für sehr primitive 'critical sections'.
    1. task switching stoppen.
    2. abwarten bis alle tasks auf anderen prozessoren beendet sind.
    3. critical section ausführen
    4. task switching wieder einschalten.
    vorteil: sehr schnell, durch die cs wird mit voller geschwindigkeit durchgerauscht, weil das task switching komplett deaktiviert ist.
    nachteil: alle tasks sind gestoppt während die cs ausgeführt wird, auch solche, die damit nichts zu tun haben.
    das war nur als beispiel gedacht, wegen hustbärs pauschalisierung, dass locks immer sehr langsam sein *müssen*. genau so hätte ich ein beispiel mit 'nem freescale S12X nennen können, der hardware-semaphoren hat und bei dem synchronisation von tasks praktisch keine CPU-zeit beansprucht, aber das wär' nun zu exotisch gewesen. sorry für die verwirrung, mit deinem problem hat das alles natürlich nichts zu tun.
    🙂



  • Apeman schrieb:

    BorisDieKlinge schrieb:

    scheduler_ticks, pending_tasks und ON ?? was sind das für funktionen, kann mir das mal jemand erklären?

    das ist nur pseudocode für sehr primitive 'critical sections'.
    1. task switching stoppen.
    2. abwarten bis alle tasks auf anderen prozessoren beendet sind.

    Was im Schnitt etliche MILLIsekunden braucht.

    3. critical section ausführen
    4. task switching wieder einschalten.
    vorteil: sehr schnell, durch die cs wird mit voller geschwindigkeit
    durchgerauscht, weil das task switching komplett deaktiviert ist.

    Wenn du das schnell nennst... naja. Da haben wir etwas andere Vorstellungen von "schnell". Schnell wäre für mich < 10nS oder sowas.

    nachteil: alle tasks sind gestoppt während die cs ausgeführt wird, auch solche, die damit nichts zu tun haben.
    das war nur als beispiel gedacht, wegen hustbärs pauschalisierung, dass locks immer sehr langsam sein *müssen*. genau so hätte ich ein beispiel mit 'nem freescale S12X nennen können, der hardware-semaphoren hat und bei dem synchronisation von tasks praktisch keine CPU-zeit beansprucht, aber das wär' nun zu exotisch gewesen. sorry für die verwirrung, mit deinem problem hat das alles natürlich nichts zu tun.
    🙂

    Locks müssen nicht immer langsam sein, gibt kein Gesetz welches das vorschreibt. Sie *sind* es bloss immer (zumindest bei > 1 CPU/Core mit shared memory).
    Guck dir den Linux Kernel an, dort werden als Locks fast ausschliesslich Spin-Locks verwendet, und das bedeutet min. 1 atomic instruction pro Lock/Unlock Paar, auf vielen Plattformen sogar 2 atomic instructions.
    Der Windows-Kernel verwendet genauso Spin-Locks. Und atomic instructions sind üblicherweise sehr sehr teuer, verglichen mit anderen Befehlen.

    Ja, das ist eine Pauschalisierung, aber ich sehe nicht wo diese falsch ist.



  • Apeman schrieb:

    Jester schrieb:

    In der WinAPI gibt's afair auch atomare Int-Operationen. Das heißt, Du kommst ganz ohne Locks und Mutexes aus.

    stimmt: http://msdn2.microsoft.com/en-us/library/ms683590.aspx

    Jo, wobei der Grund dass Locks langsam sind ja die Verwendung von atomic instructions ist.
    Faustregel für x86/x64 Systeme: wenn man mehr als 2 atomic instructions für irgendwas braucht kann man gleiche ne Spin-Lock nehmen weil's mit der Spin-Lock schneller sein wird als "Lock-Free".



  • hustbaer schrieb:

    Apeman schrieb:

    BorisDieKlinge schrieb:

    scheduler_ticks, pending_tasks und ON ?? was sind das für funktionen, kann mir das mal jemand erklären?

    das ist nur pseudocode für sehr primitive 'critical sections'.
    1. task switching stoppen.
    2. abwarten bis alle tasks auf anderen prozessoren beendet sind.

    Was im Schnitt etliche MILLIsekunden braucht.

    warum sollte es? das 'warten' heisst ja nicht, dass andere tasks ihre komplette zeitscheibe verbraucht haben müssen, sondern es wird nur gewartet, bis sie angehalten wurden d.h. sie dürfen maximal ihren aktuellen maschinenbefehl ausführen und stoppen dann. ich verstehe nicht, wieso das *milli*sekunden dauern sollte?



  • kann mir mal einer erklären, warum man das mit mutexen serialisieren muss?
    das hat ja wohl gar keinen sinn.

    [quote="BorisDieKlinge"]

    struct ThreadData{
    
     Mutex myMutex&
    
     int a,b;
    
     ThreadData(Mutex &m) : myMutex(m){}
    
     int GetA(){
       myMutex.lock();
       int tmp= a;
       myMutex.unlock();
       return tmp;
     }
    int GetB(){
       myMutex.lock();
       int tmp= b;
       myMutex.unlock();
       return tmp;
     }
    
    void SetA(int tmp){
     myMutex.lock();
     a=tmp;
     myMutex.unlock();
    }
    void SetB(int tmp){
     myMutex.lock();
     b=tmp;
     myMutex.unlock();
    }
    
    };
    


  • Apeman schrieb:

    hustbaer schrieb:

    Apeman schrieb:

    BorisDieKlinge schrieb:

    scheduler_ticks, pending_tasks und ON ?? was sind das für funktionen, kann mir das mal jemand erklären?

    das ist nur pseudocode für sehr primitive 'critical sections'.
    1. task switching stoppen.
    2. abwarten bis alle tasks auf anderen prozessoren beendet sind.

    Was im Schnitt etliche MILLIsekunden braucht.

    warum sollte es? das 'warten' heisst ja nicht, dass andere tasks ihre komplette zeitscheibe verbraucht haben müssen,

    doch

    sondern es wird nur gewartet, bis sie angehalten wurden

    wer soll sie denn anhalten?

    d.h. sie dürfen maximal ihren aktuellen maschinenbefehl ausführen und stoppen dann.

    falsch - woher sollen sie denn wissen dass sie stoppen sollen?

    ich verstehe nicht, wieso das *milli*sekunden dauern sollte?

    ist halt so.



  • jenz schrieb:

    kann mir mal einer erklären, warum man das mit mutexen serialisieren muss?
    das hat ja wohl gar keinen sinn.

    doch das macht sinn, da du die sichtbarkeit von änderungen garantieren musst.



  • sichtbarkeit von änderungen garantieren?

    was meinst du denn damit?



  • @Jenz: Andere frage, wie würdest du es tun? Was macht bei dir Sinn?



  • 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?



  • 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.


Anmelden zum Antworten