In C++ gibt es eine Möglichkeit, sperren das Objekt selbst?
Habe ich eine stl-map, die ich sein möchte, synchronisiert über mehrere threads. Derzeit habe ich...
Funktion (Modifiziert Karte)
void Modify(std::string value)
{
pthread_mutex_lock(&map_mutex);
my_map[value] = value;
pthread_mutex_unlock(&map_mutex);
}
Funktion B (Liest Karte)
std::string Read(std::string key)
{
std::string value;
pthread_mutex_lock(&map_mutex);
std::map<std::string, std::string>::iterator it = my_map.find(key);
pthread_mutex_unlock(&map_mutex);
if(it != my_map.end())
{
return it->second;
}
else
{
return "DNE";
}
}
Dies ist synchronisiert über alle threads, aufgrund des mutex. Allerdings habe ich zum sperren der mutex-Funktion B, obwohl es nicht ändern die Karte überhaupt. Gibt es eine Möglichkeit um es zu sperren my_map Objekt selbst in Eine Funktion, und nicht lock-in-Funktion B, während thread-Synchronisation. Auf diese Weise werden alle Instanzen/Aufruf von Funktion B weiterhin frei laufen, so lange, wie Eine Funktion nicht ausgeführt wird?
Dank
- Sie suchen eine Leser/Schreiber-sperren. Ich weiß, dass boost hat eine (es heißt
shared_lock
). - Pthreads scheinen schon zu:
pthread_rwlock_t
- - Funktion", B ... ist nicht zu ändern in der Karte alle". Wanna bet?
operator[]
ändern kann seine Karte. - ging darauf zu, ich hatte einen bösen Fehler vor kurzem, verursacht durch genau diese. - usefindinstead wenn Sie nicht möchten, fügen Sie das fehlende Element
- hat die pthread_rw_lock (wenn Sie schreiben) warten Sie, bis das Lesen abgeschlossen sein?
- hat die shared_lock(wenn Sie schreiben) warten Sie, bis das Lesen abgeschlossen sein?
- Ja, danke, ich vergaß, ich werde ändern Sie den code so schnell wie möglich
- Naja, die einzige andere option für operator[] würde eine exception werfen, so ist es eigentlich logisch, es ändert die map.
- ja, das ist der Punkt. Zu jeder Zeit, die Sie haben entweder keinen thread, der die Sperre hält; ein thread, der die Sperre hält für das schreiben; einen oder mehrere threads die Sperre für das Lesen. Ich nehme an, die genannten
pthread_rwlock_t
funktioniert auf die gleiche. - Es scheint, dass der pthread-Implementierung/langsamer sein, werde ich beginnen mit der boost-Implementierung und-Profil, um zu sehen, dass. Danke für die info!
- Mit der
find
iteratorRead
außerhalb der Sperre ist die schlechte Nachricht, die ich denken würde. Ein über-schreiben der zurückgegebenen element ungültig erklären kann das iterator-was in einem schrecklichen hart-zu-finden-bug. Auch Ihre Schlösser, wie hier gezeigt, sind nicht exception-sicher, wenn Sie stick mit POSIX verwenden Wachen als mitboost::shared_lock
. Irgendeinen guten Grund, um nicht pass in die params alsconst std::string&
? - Während ich dont wollen zu hinterfragen, die Entscheidungen von OP möchte ich Sie auf die Poco-Framework, welches sehr einfach zu bedienen, und zwar komplett multithreading-Unterstützung. pocoproject.org/slides/130-Threads.pdf
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sie wollen nicht nur Schloss die container, Sie wollen auch die Sperre greift in den Behälter, D. H. alle Iteratoren oder Zeiger in es. Sie verschieben müssen, um solche Zugriffe in die verschlossene region des Codes.
Gibt es wirklich keine praktische Möglichkeit, dies zu tun, die von innen auf das Objekt selbst.
find
eine exception wirft, wird der mutex wird Links gesperrt ... wahrscheinlich für immer. (Das ist wahrscheinlich gut für eine map, deren Schlüssel ist einstd::string
, aber es kann ein problem für eine Karte verwendet, deren Vergleichs-Operatoren werfen kann.)std::string
ist unwahrscheinlich zu werfen (außer für std::bad_alloc), und andere Antworten bereits abgedeckt, die Lösungen zu diesem problem.Achtung: ich habe nicht kompiliert oder getestet, aber ich habe getan, ähnliche Dinge in der Vergangenheit.
Schritt wäre eine Kontrolle der mutex-Klasse, die als solche:
Dies erspart Ihnen, alle Arten von Fragen, zum Beispiel, wenn Ihre Karte eine exception wirft.
Dann Ihr ändern wird:
Erstellen Sie einen Verweis gezählt lock-Klasse:
(Anmerkung: es wäre einfach zu verallgemeinern, um sich mit mehreren mutexen.)
In Ihrem
read
verwenden Sie die RefCntLock Klasse:Dies bedeutet, dass jedes schreiben bekommt eine Sperre, aber alles liest Freigabe einer Sperre.
RefCntLock
funktioniert. Es scheint, dass, wenn man Lesen aufgetreten ist, dann wird der Konstruktor nicht relock oder erhöhen? Sie sollten Inkrement sowieso. Auch der name der Konstruktor und Destruktor ist falsch. Nur hinzufügen, für andere schnell klar, Ihre Verwirrung. Vielen Dank für die Beantwortung.In der kommenden C++ - 17-standard, die Sie verwenden können
std::shared_mutex
undstd::shared_lock
zu ermöglichen, dass mehrere Leser exklusiven schreib-Zugriff, undstd::unique_lock
zu implementieren exklusiven Schreibzugriff.