Beispiel für boost shared_mutex (mehrere Lesevorgänge/ein Schreibvorgang)?
Lesezeit: 7 Minuten
Kevin42
Ich habe eine Multithread-App, die einige Daten häufig lesen muss, und gelegentlich werden diese Daten aktualisiert. Im Moment hält ein Mutex den Zugriff auf diese Daten sicher, aber es ist teuer, weil ich möchte, dass mehrere Threads gleichzeitig lesen können und sie nur sperren, wenn ein Update erforderlich ist (der Aktualisierungsthread könnte warten, bis die anderen Threads fertig sind). .
Ich denke, das ist was boost::shared_mutex soll tun, aber ich bin mir nicht sicher, wie ich es verwenden soll, und habe kein klares Beispiel gefunden.
Hat jemand ein einfaches Beispiel, mit dem ich anfangen könnte?
1800 INFORMATION ist mehr oder weniger korrekt, aber es gibt ein paar Probleme, die ich korrigieren wollte.
boost::shared_mutex _access;
void reader()
{
boost::shared_lock< boost::shared_mutex > lock(_access);
// do work here, without anyone having exclusive access
}
void conditional_writer()
{
boost::upgrade_lock< boost::shared_mutex > lock(_access);
// do work here, without anyone having exclusive access
if (something) {
boost::upgrade_to_unique_lock< boost::shared_mutex > uniqueLock(lock);
// do work here, but now you have exclusive access
}
// do more work here, without anyone having exclusive access
}
void unconditional_writer()
{
boost::unique_lock< boost::shared_mutex > lock(_access);
// do work here, with exclusive access
}
Beachten Sie auch, dass im Gegensatz zu einem shared_lock nur ein einzelner Thread gleichzeitig ein upgrade_lock erwerben kann, selbst wenn es nicht aktualisiert wird (was ich als unangenehm empfand, als ich darauf stieß). Wenn also alle Ihre Leser bedingte Schreiber sind, müssen Sie eine andere Lösung finden.
Nur um “eine andere Lösung” zu kommentieren. Wenn alle meine Leser bedingte Schreiber waren, ließ ich sie immer ein shared_lock erwerben, und wenn ich ein Upgrade zum Schreiben von Privilegien benötigte, würde ich die Lesersperre .unlock() und ein neues unique_lock erwerben. Dies wird die Logik Ihrer Anwendung verkomplizieren, und es gibt jetzt ein Zeitfenster für andere Autoren, den Status zu ändern, nachdem Sie ihn zum ersten Mal gelesen haben.
– mmocny
4. März 2011 um 21:30 Uhr
Sollte die Linie nicht boost::unique_lock< boost::shared_mutex > lock(lock); lesen boost::unique_lock< boost::shared_mutex > lock(_betreten); ?
– SteveWilkinson
1. April 2011 um 17:01 Uhr
Dieser letzte Vorbehalt ist sehr seltsam. Wenn jeweils nur ein Thread eine upgrade_lock halten kann, was ist dann der Unterschied zwischen einer upgrade_lock und einer unique_lock?
– Ken Smith
11. August 2011 um 0:11 Uhr
@Ken Ich war nicht sehr klar, aber der Vorteil von upgrade_lock ist, dass es nicht blockiert, wenn derzeit einige shared_locks erworben werden (zumindest nicht, bis Sie auf unique upgraden). Der zweite Thread, der versucht, eine upgrade_lock zu erwerben, wird jedoch blockiert, selbst wenn der erste nicht auf unique aktualisiert wurde, was ich nicht erwartet hatte.
boost::shared_mutex _access;
void reader()
{
// get shared access
boost::shared_lock<boost::shared_mutex> lock(_access);
// now we have shared access
}
void writer()
{
// get upgradable access
boost::upgrade_lock<boost::shared_mutex> lock(_access);
// get exclusive access
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
// now we have exclusive access
}
Dies ist das erste Mal, dass ich boost verwende, und ich bin ein C++-Neuling, also fehlt mir vielleicht etwas – aber in meinem eigenen Code musste ich den Typ angeben, etwa so: boost::shared_lock lock (_betreten);
– Ken Smith
16. März 2010 um 23:02 Uhr
Ich versuche, dies selbst zu verwenden, aber ich erhalte eine Fehlermeldung. fehlende Template-Argumente vor ‘lock’. Irgendwelche Ideen?
– Hookenz
18. August 2010 um 2:56 Uhr
@shaz Diese sind begrenzt, aber Sie können sie bei Bedarf mit .unlock() vorzeitig freigeben.
– mmocny
27. Januar 2011 um 18:23 Uhr
Ich habe die fehlenden Template-Argumente hinzugefügt.
– Benutzer283145
7. November 2012 um 22:49 Uhr
@raaj Sie können die upgrade_lock erhalten, aber das Upgrade auf eine eindeutige Sperre wird blockiert, bis die shared_lock freigegeben wird
– 1800 INFORMATIONEN
10. April 2016 um 21:27 Uhr
Yocha Timmer
Seit C++ 17 (VS2015) können Sie den Standard für Lese-Schreib-Sperren verwenden:
würde ich auch sagen typedef boost::unique_lock< Lock > WriteLock; typedef boost::shared_lock< Lock > ReadLock;.
– Reben
17. Januar 2012 um 2:11 Uhr
Sie müssen nicht die gesamte Datei thread.hpp einschließen. Wenn Sie nur die Schlösser benötigen, fügen Sie die Schlösser hinzu. Es ist keine interne Implementierung. Beschränken Sie die Includes auf das Minimum.
– Yochai Timmer
15. Februar 2014 um 17:55 Uhr
Auf jeden Fall die einfachste Implementierung, aber ich denke, es ist verwirrend, sowohl Mutexe als auch Sperren als Sperren zu bezeichnen. Ein Mutex ist ein Mutex, eine Sperre ist etwas, das es in einem gesperrten Zustand hält.
– Tim MB
13. Juli 2015 um 14:45 Uhr
Verwenden Sie ein Semaphor mit einer Anzahl, die gleich der Anzahl der Leser ist. Lassen Sie jeden Leser die Semaphore einmal zählen, um zu lesen, damit alle gleichzeitig lesen können. Lassen Sie dann den Schreiber vor dem Schreiben ALLE Semaphor-Zählungen vornehmen. Dies führt dazu, dass der Writer wartet, bis alle Lesevorgänge abgeschlossen sind, und dann Lesevorgänge während des Schreibens blockiert.
Die Terekhov algorithm sorgt dafür, dass in 1., der Schriftsteller kann die Leser nicht aushungern. Sieh dir das an. Aber 2. ist wahr. Ein upgrade_lock garantiert keine Fairness. Sieh dir das an.
– Jonas Vautherin
14. Februar 2014 um 14:50 Uhr
dale1209
Tolle Antwort von Jim Morris, ich bin darüber gestolpert und es hat eine Weile gedauert, bis ich es herausgefunden habe. Hier ist ein einfacher Code, der zeigt, dass nach dem Absenden einer “Anfrage” für einen Unique_lock-Boost (Version 1.54) alle Shared_lock-Anfragen blockiert werden. Dies ist sehr interessant, da es mir scheint, dass die Wahl zwischen unique_lock und upgradeable_lock erlaubt, ob wir Schreibpriorität oder keine Priorität wollen.
Auch (1) in Jim Morris’ Beitrag scheint dem zu widersprechen: Boost shared_lock. Bevorzugt lesen?
Ich habe tatsächlich Probleme herauszufinden, warum der obige Code Deadlocks verursacht, während der Code eingeht [stackoverflow.com/questions/12082405/… works.
– dale1209
Nov 20, 2013 at 22:00
It actually deadlocks in (2), not in (3), because (2) is waiting for (1) to release its lock. Remember: to get a unique lock, you need to wait for all the existing shared locks to finish.
– JonasVautherin
Feb 14, 2014 at 14:56
@JonesV, even if (2) waits for all shared locks to finish, it wouldn’t be a deadlock because it’s a different thread than the one which acquired (1), if line (3) didn’t exist, the program would finish with no deadlocks.
– SagiLow
Jul 5, 2017 at 12:11
I’m actually having trouble figuring out why the above code deadlocks while the code in [stackoverflow.com/questions/12082405/… works.
– dale1209
Nov 20, 2013 at 22:00
It actually deadlocks in (2), not in (3), because (2) is waiting for (1) to release its lock. Remember: to get a unique lock, you need to wait for all the existing shared locks to finish.
– JonasVautherin
Feb 14, 2014 at 14:56
@JonesV, even if (2) waits for all shared locks to finish, it wouldn’t be a deadlock because it’s a different thread than the one which acquired (1), if line (3) didn’t exist, the program would finish with no deadlocks.
– SagiLow
Jul 5, 2017 at 12:11
9893500cookie-checkBeispiel für boost shared_mutex (mehrere Lesevorgänge/ein Schreibvorgang)?yes
Das Beispiel von 1800 INFORMATION ist korrekt. Siehe auch diesen Artikel: Was ist neu in Boost-Threads.
– Assaf Lavie
13. Juni 2009 um 3:52 Uhr
mögliches Duplikat von Reader/Writer Locks in C++
– chao
23. Juni 2011 um 7:25 Uhr