CSemaphore



  • Ok vieleicht falsch ausgedrückt. Also keine Prozesse sondern mehrere Threads. Es dürfen mehrere Threads auf ein Objekt zugreifen. Allerdings darf der GUI Thread nur das Objekt löschen wenn alle anderen treads das objekt freigegeben haben. Diese müssen nicht beendet sein.


  • Mod

    Wenn die anderen nur Lesen und einer nur schreibt kannst Du zu einer Multiple-Reader Single-Writer Klasse greifen.

    Oder Du arbeitest einfach mit einem Intelligenten Zeiger (Referenzzählung).



  • Oder Du arbeitest einfach mit einem Intelligenten Zeiger (Referenzzählung).

    Genau so was und das dachte ich das löse ich mit einer Semaphore. Nur ich weiß nicht genau wie?



  • Ich habe da noch einen anderen Vorschlag:
    Wenn sich mehrere Threads eine Ressource, z.B. eine Variable oder Dateizugriff teilen müssen, dann kann der konkurrierende Zugriff auf über einen Mutex des Windows-API gesichert werden.

    Dazu muss zuerst ein Handle deklariert werden.
    Jeder Thread der den Zugriff auf die Ressource durchführen möchte ruft die GetMutex-Funktion auf. Wenn die Funktion mit true beendet wird, so darf der Thread auf die Ressource zugreifen. Ist die Ressource bereits zuvor durch einen anderen Thread mit GetMutex erfolgreich belegt worden, so bleibt der Thread in der Funktion GetMutex stecken und wartet bis zum Timeout (MUTEX_TIMEOUT) ob die Ressource frei wird. Wird sie allerdings nicht innerhalb dieser Timeoutzeit frei, bekommt man bei GetMutex ein false zurück, kann etwas unternehmen und ggfs. wieder GetMutex aufrufen. Wenn ein Thread mit dem Zugriff auf die Ressource fertig ist, so muss sie unbedingt RelMutex()
    aufrufen, um die Ressource für die anderen Threads freizugeben. Falls gerade ein anderer Thread in der GetMutex-Funktion wartet, so wird er vom Betriebssystem als nächster auf die Ressource freigegeben, d.h. er bekommt den Mutex.

    Im meinem Beispiel ist das ganze nicht als Klasse implementiert, sondern als globale Funktionen. Die Funktion InitMutex() muss nicht aufgerufen werden, da das automatisch beim ersten GetMutext() passiert.

    #define MUTEX_TIMEOUT 60000
    
    HANDLE hMutex=0;
    void InitMutex()
    {
    	hMutex = CreateMutex(0,0,"Name der Ressorce");  
    
    	if(!hMutex) QuitAbbruch(..........);
    }
    
    bool GetMutex()
    {
    	if(!hMutex) InitMutex();
    
    	if(!WaitForSingleObject(hMutex,MUTEX_TIMEOUT)) return 1;
    	else                                           return 0;
    }
    
    void RelMutex()
    {
    	if(hMutex) ReleaseMutex(hMutex);
    }
    

    Dieses Verfahren habe ich bereits in mehreren großen Projekten verwendet und bin damit sehr zufrieden.

    Viele Grüße
    JoyPaD



  • Hallo. Ok nochmal. Alle Threads dürfen gleichzeitig auf das Objekt zugreifen. Da brauche ich keinen mechanismus dafür. Brauche eigentlich nur einen Counter der die Zugriffe auf das Objekt zählt und nur wenn der Counter = 0 ist darf das Objekt gelöscht werden.

    Dafür bruche ich meiner Meinung nach eine Semaphore. Nur ich weiß nicht wie anwenden. Kann mir dazu niemand konkrett helfen?



  • Wenn du nur mit zählen willst, ob auf das Objekt zugegriffen wird, reicht doch ein integer...
    Oder geh ich jetzt all zu blauäugig drauf los?



  • ... da wäre ich vorsichtig. ggfs. wird der zugriff durch das Multithreading zerhackt und der Integer ist nicht mehr konsistent.


  • Mod

    JoYpaD schrieb:

    ... da wäre ich vorsichtig. ggfs. wird der zugriff durch das Multithreading zerhackt und der Integer ist nicht mehr konsistent.

    Der Zugriff auf aligned Integer ist IMHO auf allen Rechnern atomar und wird nicht durch einen context switch eines Threads zerhackt.



  • Es können aber Probleme durch re-ordering auftreten.
    Also mindestens InterlockedXX benutzen.
    Simon



  • Achso. Und mit einer Semaphore läst sich das nicht lösen?



  • Oder Du arbeitest einfach mit einem Intelligenten Zeiger (Referenzzählung).

    Wenn mir noch jemand erklären würde wie das funktioniert wäre ich glücklich 🙂



  • In der Funktion B Warte ich mit CSingleLock(&m_semaphaphore). Doch hier wartet nun mein Programm nicht sondern läuft durch. Wieso

    Könnte man mir eine einfache Antwort geben. Auf genau diese Frage!


  • Mod

    Weil es evtl. der selbe Thread ist?



  • Wenn ich die MSDN-Doku eben richtig überflogen habe, dann musst Du in der Lösch-Methode so darauf warten, dass alle anderen Threads draußen sind:

    CSingleLock singleLock(&m_CritSection);
    singleLock.Lock();  // Attempt to lock the shared resource
    if (singleLock.IsLocked())  // Resource has been locked
    {
    //...use the shared resource...
    
    // Now that we are finished, 
    // unlock the resource for others.
    singleLock.Unlock();
    }
    

  • Mod

    Warum verwendest Du keine Smart Pointer?

    Der Main-Thread erzeugt die Daten und übergibt die Smart-Pointer an die Threads.
    Wenn die lette Referenz weg ist, zerstört sich das Objekt von selbst.



  • @ JoYpaD

    Das ist doch das selbe wie

    CSingleLock singleLock(&m_CritSection,TRUE);
    

    mit dem 2ten Parameter wird gleich gelockt. Mit

    singleLock.IsLocked()
    

    warte ich ja nicht das ist ja nur nochmals eine Sicherheitsabfrage. Ob gelockt wurde.



  • Weil es evtl. der selbe Thread ist?
    

    Nein ist es nicht. Das Problem ist ja dass ich meine Semaphore mit 5 initialisiert habe. Sprich 5 Threads dürfen gleichzeitig zugreifen. Was ich ja aber will ist dass 5 Threads das Objekt sperren dürfen. Die Löschfunktion muss aber warten bis alle laufenden Threads beendet sind. Mit CSingleLock dachte ich erreiche das. Jedoch sieht es nun für mich so aus dass ich mit CSingleLock auch in die 5 erlaubten Threads einreihe. Also ob ich nun m_semaphore.Lock mache oder CSingleLock(m_semaphore,TRUE). Kommt eigentlich auf das selbe raus.

    Jetzt ist ja nur die Frage wie schaffe ich es dass die 5 Threads darauf zugreifen dürfen die Löschfunktion aber nur wenn alle beendet sind.

    Martin Richter schrieb:

    Wenn die lette Referenz weg ist, zerstört sich das Objekt von selbst.

    Das solls ja ber nicht. Das Objekt soll nur zerstört werden wenn die Löschfunktion aufgerufen wird. Die wird aber nicht zwingend aufgerufen wenn alle Thrads beendet sind. Sie darf nur nicht ausgeführt werden wenn noch einer am Laufen ist


  • Mod

    Eben. Im Destruktor wird die Löschfunktion aufegrufen.
    Wenn noch eine Referenz existiert (also ein Thread läuft) wird eben nicht gelöscht.

    Ich glaube Du hast da ein totales Code Chaos und hast Semaphoren nicht verstanden.



  • Im Destruktor wird die Löschfunktion aufegrufen.

    Na eben nicht.

    Wenn noch eine Referenz existiert (also ein Thread läuft) wird eben nicht gelöscht.

    Richtig aber wie verhindere ich das. Das ist ja meine Frage

    Ich glaube Du hast da ein totales Code Chaos und hast Semaphoren nicht verstanden.

    Ok dann habe ich halt Semaphore nicht verstanden. Drum frage ich ja hier.


  • Mod

    tanztderbär schrieb:

    Im Destruktor wird die Löschfunktion aufegrufen.

    Na eben nicht.

    Wenn noch eine Referenz existiert (also ein Thread läuft) wird eben nicht gelöscht.

    Richtig aber wie verhindere ich das. Das ist ja meine Frage

    Also nochmal gaaaaaanz langsam zum mitschreiben.

    1. Du baust ein Containerobjekt.
    In dessen Destruktor wird aufgeräumt, so wie Du möchtest
    2. Nun Erzeugst Du dieses Objekt und weist es einem Smart-Pointer zu (es gibt counted pointer, linked pointer), alles wurscht. Hauptsache threadsafe (siehe Boost (http://www.boost.org/doc/libs/1_40_0/libs/smart_ptr/smart_ptr.htm) oder hier http://ootips.org/yonat/4dev/smart-pointers.html.
    3. Nun bekommt jeder Thread eine Kopie des Smartpointers.
    4. Der aufrufende Thread kann nun den Smartpointer vergessen und freigeben.
    5. Nachdem der letzte Thread stirbt räumt der Container auf.

    Das habe ich doch schon so angeraten.
    Das funktioniert ganz unabhängig von der Anzahl der User.

    BTW: Der Smartpointer Code muss evtl. noch mit Interlocked Funktionen threasicher gemacht werden. (Ist bei Boost nicht notwendig).


Anmelden zum Antworten