Fädle einen sicheren Behälter

8

Es gibt einige beispielhafte Klassen von Containern in Pseudocode:

%Vor%

Wie kann dieser Behälter fadensicher gemacht werden? Ich habe von Mutexen gehört - wo sollten diese Mutexe platziert werden? Sollte Mutex für eine Klasse statisch oder vielleicht global sein? Was ist eine gute Bibliothek für diese Aufgabe in C ++?

    
scdmb 07.10.2011, 07:49
quelle

5 Antworten

8

Zunächst sollten Mutexe für eine Klasse nicht statisch sein, solange Sie mehr als eine Instanz verwenden. Es gibt viele Fälle, in denen Sie sie verwenden sollten oder sollten. Also, ohne Ihren Code zu sehen, ist es schwer zu sagen. Denken Sie daran, sie werden verwendet, um den Zugriff auf gemeinsame Daten zu synchronisieren. Daher ist es ratsam, sie in Methoden zu platzieren, die den Status des Objekts ändern oder sich darauf verlassen. In Ihrem Fall würde ich einen Mutex verwenden, um das ganze Objekt zu schützen und alle drei Methoden zu sperren. Wie:

%Vor%     
GreenScape 07.10.2011, 07:58
quelle
4

Intel-Thread-Building-Blocks (TBB) bieten eine Reihe von Thread-sicheren Container-Implementierungen für C ++. Es ist Open Source, Sie können es herunterladen von: Ссылка .

    
Vilas 07.10.2011 07:56
quelle
1

Mutex als Instanzvariable der Klasse hinzufügen. Initialisieren Sie es im Konstruktor, und sperren Sie es am Anfang jeder Methode, einschließlich des Destruktors, und entsperren Sie es am Ende der Methode. Das Hinzufügen eines globalen Mutex für alle Instanzen der Klasse (statischer Member oder nur im globalen Gültigkeitsbereich) kann eine Leistungseinbuße darstellen.

    
Alexander B 07.10.2011 08:12
quelle
1

Das ist auch eine sehr schöne Sammlung von Lock-Free-Containern (einschließlich Karten) von Max Khiszinsky

LibCDS 1 Gleichzeitige Datenstrukturen

Hier ist die Dokumentationsseite:

Ссылка

Es kann etwas einschüchternd sein, um loszulegen, da es vollständig generisch ist und erfordert, dass Sie eine gewählte Speicherbereinigungsstrategie registrieren und diese initialisieren. Natürlich ist die Threading-Bibliothek konfigurierbar und Sie müssen das auch initialisieren:)

Siehe die folgenden Links für einige erste Informationen:

Hier ist die Basisvorlage für 'main':

%Vor%

Vergessen Sie nicht, zusätzliche Threads anzuhängen, die Sie verwenden:

%Vor%

1 ( darf nicht mit der kompakten Datenstrukturbibliothek von Google verwechselt werden)

    
sehe 07.10.2011 08:37
quelle
1

Erstens: Austauschbare Zustände zwischen Threads sind schwer . Sie sollten eine Bibliothek verwenden, die geprüft und debuggt wurde.

Nun, da es gesagt wird, gibt es zwei verschiedene funktionale Probleme:

  • Sie möchten, dass ein Container sichere atomare Operationen
  • bereitstellt
  • Sie möchten, dass ein Container sichere mehrere Operationen
  • bereitstellt

Die Idee mehrerer Operationen besteht darin, dass mehrere Zugriffe auf denselben Container nacheinander unter der Kontrolle einer einzelnen Entität ausgeführt werden müssen. Sie erfordern, dass der Aufrufer den Mutex für die Dauer der Transaktion "hält", so dass nur it den Status ändert.

1. Atomare Operationen

Dieser erscheint einfach:

  • fügen Sie dem Objekt einen Mutex hinzu
  • Zu Beginn jeder Methode ein Mutex mit einer RAII-Sperre

Leider ist es auch einfach falsch.

Das Problem ist Re-Entrance. Es ist wahrscheinlich, dass einige Methoden andere Methoden für dasselbe Objekt aufrufen. Wenn diese wieder versuchen, den Mutex zu greifen, erhalten Sie eine totale Sperre.

Es ist möglich, einspringende Mutexe zu verwenden. Sie sind etwas langsamer, erlauben es aber demselben Thread, einen bestimmten Mutex so weit wie möglich zu sperren. Die Anzahl der Freischaltungen sollte der Anzahl der Sperren entsprechen, also noch einmal RAII.

Ein anderer Ansatz besteht darin, Dispatch-Methoden zu verwenden:

%Vor%

Die public -Methoden sind einfache Weiterleitungen zu private work-methods und sperren einfach. Dann muss man nur sicherstellen, dass private Methoden niemals den Mutex nehmen ...

Natürlich gibt es Risiken, dass Sie versehentlich eine Sperrmethode von einer Arbeitsmethode aus aufrufen. In diesem Fall blockieren Sie. Lesen Sie weiter, um dies zu vermeiden;)

2. Mehrere Operationen

Das kann nur erreicht werden, wenn der Anrufer den Mutex hält.

Die allgemeine Methode ist einfach:

  • fügen Sie dem Container einen Mutex hinzu
  • bietet ein Handle für diese Methode
  • Daumen drücken, dass der Anrufer niemals vergessen wird, den Mutex beim Zugriff auf die Klasse
  • zu halten

Ich persönlich bevorzuge einen viel gesunden Ansatz.

Zuerst erstelle ich ein "Datenbündel", das einfach die Klassendaten darstellt (+ ein Mutex), und dann stelle ich ein Proxy bereit, das den Mutex ergreift. Die Daten sind gesperrt, so dass der Proxy nur auf den Status zugreifen kann.

%Vor%

Beachten Sie, dass es vollkommen sicher ist, dass der Proxy seine eigenen Methoden aufruft. Der Mutex wird automatisch vom Destruktor freigegeben.

Der Mutex kann immer noch reentrant sein, wenn mehrere Proxys gewünscht werden. Aber wirklich, wenn mehrere Proxies beteiligt sind, wird es in der Regel zu einem Durcheinander. Im Debug-Modus ist es auch möglich, eine "Überprüfung" hinzuzufügen, dass der Mutex nicht bereits von diesem Thread gehalten wird (und bestätigen, wenn dies der Fall ist).

3. Erinnerung

Die Verwendung von Sperren ist fehleranfällig. Deadlocks sind eine häufige Fehlerursache und treten auf, sobald Sie zwei Mutexe (oder einen und Re-Entrance) haben. Wenn möglich, bevorzugen Sie höherwertige Alternativen.

    
Matthieu M. 07.10.2011 10:35
quelle

Tags und Links