Warum Mutex als Parameter an eine Funktion übergeben wird, die von einem Thread aufgerufen wird?

8

An einigen Stellen habe ich Leute gesehen, die einen Thread-Pool erstellt und Threads erstellt und eine Funktion mit diesen Threads ausgeführt haben. Beim Aufruf dieser Funktion wird boost :: mutex als Referenz übergeben. Warum ist es so? Ich glaube, man kann einen Mutex in der aufgerufenen Funktion selbst deklarieren oder als Klassenmitglied oder Global deklarieren. Kann mir bitte jemand erklären?

z.B.

%Vor%

Dann,

%Vor%     
polapts 26.09.2011, 12:49
quelle

3 Antworten

10

Mutex's sind nicht kopierbare Objekte, und obwohl sie Mitglieder einer Klasse sein können, würde dies die Kopierfähigkeit einer Elternklasse stark verkomplizieren. Wenn also eine Anzahl von Klasseninstanzen die gleichen Daten teilen soll, wäre es eine bevorzugte Methode, den Mutex als statisches Datenelement zu erstellen. Andernfalls, wenn der Mutex nur innerhalb einer Instanz der Klasse selbst gesperrt werden müsste, könnten Sie einen Zeiger auf einen Mutex als nicht-statisches Datenelement erstellen, und dann würde jede Kopie der Klasse ihren eigenen dynamisch zugewiesenen Mutex (und kopierbar bleiben, wenn dies eine Voraussetzung ist).

Im obigen Codebeispiel wird im Grunde genommen ein globaler Mutex durch Verweis in den Thread-Pool eingefügt. Dadurch können alle Threads, die sich die gleichen Speicherorte teilen, eine exklusive Sperre für diesen Speicher unter Verwendung des exakt gleichen Mutex erstellen, jedoch ohne den Aufwand, den nicht kopierbaren Aspekt des Mutex selbst verwalten zu müssen. Der Mutex in diesem Codebeispiel könnte auch ein statisches Datenelement der Klasse myClass gewesen sein, anstelle eines globalen Mutex, der als Referenz übergeben wird, wobei vorausgesetzt wird, dass jeder Thread etwas Speicher sperren muss, auf den global zugegriffen werden kann thread.

Das Problem mit einem lokalen Mutex ist, dass es nur eine lokal zugängliche Version des Mutex ist ... wenn also ein Thread den Mutex sperrt, um einige global zugängliche Daten zu teilen, sind die Daten selbst nicht geschützt, da jeder andere Thread wird seinen eigenen lokalen Mutex haben, der gesperrt und entsperrt werden kann. Es besiegt den ganzen Punkt der gegenseitigen Ausgrenzung.

    
Jason 26.09.2011, 12:55
quelle
1
  

Ich glaube, Sie können einen Mutex in der aufgerufenen Funktion selbst deklarieren oder er kann als Klassenmitglied oder global deklariert werden. Kann mir bitte jemand erklären?

das Erstellen eines neuen Mutex am Eintrag schützt nichts.

Wenn Sie erwägen, einen statischen (oder globalen) Mutex zu deklarieren, um nicht-statische Member zu schützen, dann können Sie das Programm auch als ein Single-Thread-Programm schreiben (ok, es gibt einige Eckfälle). Eine statische Sperre würde alle Threads bis auf einen blockieren (unter der Annahme eines Wettbewerbs); es ist äquivalent zu "maximal ein Thread kann gleichzeitig im Körper dieser Methode arbeiten". Einen statischen Mutex zu deklarieren, um statische Daten zu schützen, ist in Ordnung. wie David Rodriguez - Dribeas es in den Kommentaren einer anderen Antwort kurz formulierte: "Der Mutex sollte auf der Ebene der Daten sein, die geschützt werden".

Sie können eine Membervariable pro Instanz deklarieren, die die verallgemeinerte Form annehmen würde:

%Vor%

Dieser Ansatz ist in Ordnung und in einigen Fällen ideal . Es ist in den meisten Fällen sinnvoll, wenn Sie ein System aufbauen, in dem Instanzen beabsichtigen, Sperrmechanismen und Fehler von ihren Clients zu abstrahieren. Ein Nachteil ist, dass es mehr Akquisitionen erfordern kann, und es erfordert typischerweise komplexere Sperrmechanismen (z. B. Wiedereintritt). durch mehr Akquisitionen: Der Client weiß vielleicht, dass eine Instanz nur in einem Thread verwendet wird: Warum überhaupt sperren? Außerdem wird eine Reihe von Methoden mit kleinen ThreadSafe eine Menge Overhead einführen. Beim Sperren möchten Sie so schnell wie möglich in die geschützten Zonen ein- und aussteigen (ohne viele Erfassungen vorzunehmen), so dass die kritischen Abschnitte oft größere Operationen als typisch sind.

Wenn die öffentliche Schnittstelle diese Sperre als Argument benötigt (wie in Ihrem Beispiel), ist dies ein Signal dafür, dass Ihr Design durch Privatisierung der Sperrung vereinfacht werden kann (die Objektfunktion wird threadsicher gemacht) , anstatt das Schloss als extern gehaltene Ressource zu übergeben.)

Mit einer externen (oder gebundenen oder verknüpften) Sperre können Sie möglicherweise die Anzahl der Erfassungen (oder die gesamte Zeitsperre) reduzieren. Mit diesem Ansatz können Sie auch nachträglich eine Sperre zu einer Instanz hinzufügen. Außerdem kann der Client konfigurieren, wie das Schloss funktioniert. Der Client kann weniger Sperren verwenden, indem er sie gemeinsam nutzt (in einer Reihe von Instanzen). Auch ein einfaches Beispiel für Komposition kann dies illustrieren (unterstützt beide Modelle):

%Vor%

Wenn man die Komplexität mancher Multithread-Systeme betrachtet, kann es eine sehr schlechte Idee sein, die Verantwortung für das richtige Sperren auf den Client zu übertragen.

Beide Modelle (gebunden und als Elementvariable) können effektiv verwendet werden. Was in einem gegebenen Szenario besser ist, variiert je nach Problem.

    
justin 26.09.2011 14:14
quelle
0

Die Verwendung von lokalem Mutex ist falsch: Thread-Pool kann mehrere Funktionsinstanzen aufrufen und sie sollten mit demselben Mutex arbeiten. Klassenmitglied ist in Ordnung. Das Übergeben von Mutex an die Funktion macht es generischer und lesbarer. Der Anrufer kann entscheiden, welcher Mutex übergeben wird: Klassenmitglied oder irgendetwas anderes.

    
Alex F 26.09.2011 12:56
quelle

Tags und Links