2010-11-17 6 views
7

Ich habe mehrere Threads, die einen STL-Vektor und eine STL-Liste modifizieren.
Ich möchte eine Sperre nehmen um zu vermeiden, wenn der BehälterIst STL leer() threadsafe?

würde der folgende Code sein THREAD leer ist? Was wäre, wenn Elemente eine Liste oder eine Karte wären?

class A 
{ 
    vector<int> items 
    void DoStuff() 
    { 
     if(!items.empty()) 
     { 
      AquireLock(); 
      DoStuffWithItems(); 
      ReleaseLock(); 
     } 
    } 
} 
+0

Danke für die Antworten. Um die Frage zu klären: Ein weiterer Thread wird zu den Elementen hinzugefügt. Kein anderer Thread wird von Elementen entfernt - Löschvorgänge werden nur innerhalb von DoStuffWithItems() ausgeführt und nur ein einzelner Thread ruft DoStuff() auf. Es ist in Ordnung, wenn items.empty() false zurückgibt, während ein anderer Thread es hinzufügt. Es ist nicht in Ordnung, wenn items.empty() dazu führt, dass die Anwendung abstürzt, wenn ein anderer Thread hinzugefügt wird –

Antwort

6

Es hängt davon ab, was Sie erwarten. Die anderen Antworten sind richtig, dass im Allgemeinen, C++ - Standardcontainer sind nicht thread-sicher, und außerdem, dass insbesondere Ihr Code nicht gegen einen anderen Thread die Änderung des Containers zwischen Ihrem Anruf an empty und den Erwerb der Schloss (aber diese Angelegenheit hat nichts mit der Gewindesicherheit von vector::empty zu tun).

Also, um Missverständnisse abzuwenden: Ihr Code garantiert nicht items wird nicht leer innerhalb des Blocks.

Aber Ihr Code kann immer noch nützlich sein, da Sie nur redundante Lock-Kreationen vermeiden wollen. Ihr Code gibt keine Garantien, aber es kann verhindern eine unnötige Sperre erstellen. Es funktioniert nicht in allen Fällen (andere Threads können immer noch den Container zwischen Ihrem Scheck und der Sperre leeren), aber in einige Fälle. Wenn Sie nur nach einer Optimierung suchen, indem Sie eine redundante Sperre ausschließen, erreicht Ihr Code dieses Ziel.

So stellen Sie sicher, dass jeder tatsächliche Zugang zum Behälter durch Sperren geschützt ist.

By the way, die oben ist streng genommen undefinierten Verhalten: eine STL-Implementierung theoretisch mutable Mitglieder innerhalb der Anruf erlaubt ist empty zu ändern. Dies würde bedeuten, dass der scheinbar harmlose (weil nur lesbare) Ruf zu empty tatsächlich einen Konflikt verursachen kann. Leider können Sie nicht verlassen auf der Annahme, dass schreibgeschützte Aufrufe mit STL-Containern sicher sind.

In der Praxis aber, bin ich ziemlich sicher, dass vector::empty wird nichtkeine Mitglieder ändern.Aber schon für list::empty bin ich weniger sicher. Wenn Sie wirklich wollen Garantien, dann sperren Sie entweder alle Zugriff oder verwenden Sie nicht die STL-Container.

1

STL ist nicht Thread sicher und leer auch. Wenn Sie Container sicher machen möchten, müssen Sie alle Methoden durch Mutex oder eine andere Synchronisierung schließen.

3

Es gibt keine thread-safe Garantie auf irgendetwas in den Containern und Algorithmen der STL.

So, Nr

2

Unabhängig davon, ob oder nicht leer ist Thread-sicher, wird Ihr Code nicht, wie geschrieben, Ihr Ziel zu erreichen.

class A 
{ 
    vector<int> items 
    void DoStuff() 
    { 
     if(!items.empty()) 
     { 
      //Another thread deletes items here. 
      AquireLock(); 
      DoStuffWithItems(); 
      ReleaseLock(); 
     } 
    } 
} 

Eine bessere Lösung ist es, jedes Mal, wenn Sie mit items arbeiten zu sperren (wenn Iterieren, Items bekommt, Hinzufügen von Elementen, Zähl-/Leere Kontrolle, etc.), so dass Sie Ihre eigene Thread Sicherheit. Also, erlange zuerst die Sperre, dann überprüfe, ob der Vektor leer ist.

+0

Ihr Punkt (// Ein anderer Thread löscht hier Elemente.) Ist klar. Es ist jedoch auch offensichtlich, dass Sie nach dem Erfassen der Sperre leer() überprüfen können, um sicher zu sein. –

+0

@skwllsp: Ein gültiger Punkt. Wenn 'empty()' threadsicher ist, kann eine unnötige Sperre vermieden werden. – Brian

0

Wie bereits beantwortet, ist der obige Code nicht threadsicher und Sperren ist zwingend erforderlich, bevor tatsächlich etwas mit dem Container zu tun. Aber die folgenden sollten eine bessere Leistung als immer sperren und ich kann nicht einen Grund, dass es unsicher sein kann. Die Idee hier ist, dass das Sperren teuer sein kann und wir es vermeiden, wenn es nicht wirklich benötigt wird.

class A 
{ 
    vector<int> items; 
    void DoStuff() 
    { 
     if(!items.empty()) 
     { 
      AquireLock(); 
      if(!items.empty()) 
      { 
       DoStuffWithItems(); 
      } 
      ReleaseLock(); 
     } 
    } 
}