Ich versuche, eine Karte zu schreiben, die threadsicher ist, aber niemals beim Lesen blockiert oder blockiert. Ich versuche, eine schreibgeschützte Map zu verwenden, die beim Schreiben kopiert wird. Die Idee ist get() ist sperren-frei, und put() kopiert die aktuelle schreibgeschützte unterliegende Karte zu einem neuen, tut das Put und tauscht die aktuelle zugrunde liegende Karte für ein neues aus. (Ja, put() ist ineffizient, da sie kopiert die gesamte Karte, aber ich interessiere mich nicht für meinen Anwendungsfall)Algorithmus für eine einfache nicht-locking-on-lesen gleichzeitige Karte?
Meinen ersten Stich an dieser std verwendet :: Atom < * StringMap> für den Read-Only Karte ABER es ist ein großer Fehler mit diesem, wahrscheinlich aufgrund meiner Java-Hintergrund. get() erhält atomar einen Zeiger auf die zugrunde liegende Karte, die die aktuelle sein kann oder nicht, wenn es es lädt (was in Ordnung ist). Aber put() löscht die zugrunde liegende Karte, nachdem sie es für die neue austauscht. Wenn get() ruft die alte Karte gerade als es gelöscht wird, wird dies offensichtlich zum Absturz bringen.
Ein Freund von mir vorgeschlagen shared_ptr, aber er ist nicht sicher, ob die shared_ptr-Operationen schließen unter den Abdeckungen.
Die Doktoren sagen, dass es thread-safe ist, obwohl.
Edit: Wie Nosid darauf hinweist, ist es nicht threadsicher und ich brauche die spezielle atomare Operation von std :: atomic.
Also meine Fragen sind: 1. Ist dieser Algorithmus realisierbar? 2. Führen shared_ptr-Operationen Sperren aus, besonders beim Zugriff?
#include <unordered_map>
#include <atomic>
#include <pthread.h>
#include <memory>
typedef std::unordered_map<std::string, std::string> StringMap;
class NonBlockingReadMap {
private:
pthread_mutex_t fMutex;
std::shared_ptr<StringMap> fspReadMapReference;
public:
NonBlockingReadMap() {
fspReadMapReference = std::make_shared<StringMap>();
}
~NonBlockingReadMap() {
//so, nothing here?
}
std::string get(std::string &key) {
//does this access trigger any locking?
return fspReadMapReference->at(key);
}
void put(std::string &key, std::string &value) {
pthread_mutex_lock(&fMutex);
std::shared_ptr<StringMap> spMapCopy = std::make_shared<StringMap>(*fspReadMapReference);
std::pair<std::string, std::string> kvPair(key, value);
spMapCopy->insert(kvPair);
fspReadMapReference.swap(spMapCopy);
pthread_mutex_unlock(&fMutex);
}
void clear() {
pthread_mutex_lock(&fMutex);
std::shared_ptr<StringMap> spMapCopy = std::make_shared<StringMap>(*fspReadMapReference);
fspReadMapReference.swap(spMapCopy);
spMapCopy->clear();
pthread_mutex_unlock(&fMutex);
}
};
„ist ineffizient, da es kopiert die gesamte Karte, aber ich interessiere mich nicht für meinen Anwendungsfall“ - Dann sind Sie sicher, dass Sie die Komplexität eines Tiered-Locking-Schemas benötigen? –
@BrianCain - für meinen Anwendungsfall ja. Mehrere Threads werden ständig get(). put() s wird nach einer anfänglichen Startblase selten (Tage/Wochen auseinander) sein. – marathon
Es gibt einen Port von Java's nicht-blockierenden Hashmapp für C++, warum nicht zuerst schauen? Wenn sie die zugrunde liegende FSM korrekt implementiert haben, erhalten Sie sogar Korrektheitsbeweise für die Implementierung. Und wenn nicht, haben Sie zumindest ein bewährtes Konzept. – Voo