"Thread-sicher"



  • Hi!

    Was bedeutet es eigentlich, eine Klasse thread-sicher zu programmieren?



  • Das mehrere Threads auf Funktionen und Variablen dieser Klasse zugreifen können ohne sich im Weg zu sein.
    Dh. z.B.:
    Wenn ein Thread den Inhalt einer Variable ändert kann kein anderer auslesen da dem Thread beim schreiben in die Variable die Rechenzeit weggenommen werden kann un er deshalb mit dem schreiben nicht fertig wurde. Wenn in dieser Zeit ein anderer Thread auslesen möchte bekommt er im harmlosesten Fall nur Blödsinn geliefert.



  • Interessant, hatten wir erst gestern bei der "Konkurrenz": http://www.c-plusplus.net/ubb/cgi-bin/ultimatebb.cgi?ubb=get_topic&f=5&t=000502

    Das gesagte gilt genauso für Win32. Eine Klasse ist ja durch mehrere Attribute (Membervariablen) gekennzeichnet, z.B. ein Punkt x,y.

    Angenommen Du hast nun ein setX und setY. Ein Thread schreibt, ein Thread liest. Du willst den Punkt 1,1 auf 2,2 setzen.

    1,1 liegt an, Thread2 liest: 1,1
    setX(2); Thread2 sieht: 2,1
    setY(2); Thread2 sieht: 2,2

    Nicht ganz der gewünschte Effekt, oder? Vor allem weil dies je nach Aufrufintervall und Priorität mehr oder weniger oft und stark passieren kann.

    Daher macht man sowas:
    1,1 liegt an, Thread2 liest: 1,1
    LOCK Thread2 kann nicht auf Punkt zugreifen und wird angehalten
    setX(2);
    setY(2);
    UNLOCK
    2,2 liegt an, Thread2 darf wieder und liest 2,2

    Übrigens, der Gedanke eine Funktion setXY(2,2) einzuführen ist NICHT ausreichend, weil ein Thread nach jedem Assemblerbefehl unterbrechen kann. Sogar ein (*i)++ könnte noch unterbrochen werden wenn's dumm läuft.

    Dafür gibt's diese Lockobjekte. Parallel zu den Funktionen im Linux-Thread hat Win32 die Funktionen CreateMutex, OpenMutex, usw. Siehe MSDN.

    Wenn eine Klasse obige Eigenschaften erfüllt, daß also sichergestellt ist daß kein Thread zwischendurch nur halb veränderte Werte lesen kann, dann spricht man von einer threadsicheren Klasse.



  • Wie ist das ganze beim Borland C++ Builder. Ich habe da nichts von Lock, Unlock gelesen. Verwendet man dort Synchronize um das ganze Threadsicher zu machen? Oder habe ich da etwas falsch verstanden?

    Cain Adams

    [ 22.08.2001: Beitrag editiert von: CainAdams ]



  • Du kannst natürlich auch auf dem Builder die normalen Win32-Funktionen dafür verwenden... CreateMutex und Konsorten.

    Bei der MFC gibt es dafür die Klassen CCriticalSection und CSingleLock.

    Bei der VCL TCriticalSection mit den Methoden "Enter()" und "Leave()".



  • Wie kann ich denn ein Mutex einsetzen?

    z.B. bei der Klasse Point:

    class Point
    {
    public:
      void SetX(int x) {m_x = x;}
      void SetY(int y) {m_y = y;}
    
      int GetX() const {return m_x;}
      int GetY() const {return m_y;}
    
    private:
      int m_x;
      int m_y;
    };
    

    Wie muss ich das verändern um es thread-sicher zu machen?

    [ 22.08.2001: Beitrag editiert von: cd9000 ]

    [ Dieser Beitrag wurde am 14.12.2001 um 23:12 Uhr von Marc++us editiert. ]



  • class Point
    {
    public:
       void setXY(int x, int y)
       {
          LOCK();
          m_x = x;
          m_y = y;
          UNLOCK();
       };
    
       void getXY(int& x, int& y)
       {
          LOCK();
          x = m_x;
          y = m_y;
          UNLOCK();
       };
    
    private:
       int m_x;
       int m_y;
    };
    

    Ich habe jetzt mal allgemein LOCK/UNLOCK geschrieben, das muß man nun noch entsprechend anpassen... bei dem Linuxthread siehst Du wiederum dazu die Details, wo welche Methode eingebunden werden muß.

    Wenn Du weiterhin setX/setY getrennt haben willst, mußt Du dem Benutzer die Möglichkeit eines Lock/Unlock geben (also public-Members dafür anbieten). Davon rate ich aber eher ab, weil er das zu leicht vergiesst. Also alle Parameter zusammenpacken und gemeinsam intern dann zuweisen.



  • Ich meinte eigentlich welche Funktionen ich einsetzen muss. Ich hab das halt noch nie gemacht und aus der MSDN werd ich nicht schlau.



  • Als erstes musst Du den Mutex mit CreateMutex erstellen. Willst Du den Mutex über mehrere Prozesse hinweg verwenden, kannst Du Dir in den anderen Prozessen das Handle über OpenMutex (oder wieder CreateMutex) holen.
    Marc++s LOCK entspricht WaitForSingleObject, UNLOCK entspricht ReleaseMutex.
    Und am Ende aufräumen mit CloseHandle



  • solltest du keine Prozess übergreifende Variante brauchen, solltest du lieber eine Critical Section nehmen .. ( Perfomance )..
    "LOCK()" und "UNLOCK()" könntest du .. solltest du faul sein images/smiles/icon_wink.gif in eine Klasse ( CLock?!? )packen ( LOCK in den Konstruktor und UNLOCK in den Destructor ).. dann brauchst du nur noch folgendes schreiben

    class Point
    {
    public:
       void setXY(int x, int y)
       {
          CLock lock;
          m_x = x;
          m_y = y;
       };
     // ... rest hier 
    };
    

    .. damit vermeidest du auch das du "ausversehen" das Unlock vergisst.
    ( in der MSDN brauchst du nur mal nach Critical Section oder. Mutex suchen .. es gibt sogar Bsp Code , wenn du aus der Beschreibung nicht schlau wirst )


Anmelden zum Antworten