Ich muss eine Lese- / Schreibsperre in C ++ implementieren, indem ich Win32 api als Teil eines Projekts bei der Arbeit benutze. Alle vorhandenen Lösungen verwenden Kernel-Objekte (Semaphore und Mutexe), die während der Ausführung einen Kontextwechsel erfordern. Das ist viel zu langsam für meine Anwendung.
Ich möchte, wenn möglich, nur eine mit kritischen Abschnitten implementieren. Das Schloss muss nicht prozesssicher sein, nur threadsafe. Irgendwelche Ideen, wie man das macht?
Ich denke nicht, dass dies ohne die Verwendung mindestens eines Kernel-Level-Objekts (Mutex oder Semaphore) möglich ist, weil Sie die Hilfe des Kernels benötigen, um den aufrufenden Prozessblock zu blockieren, bis die Sperre verfügbar ist.
Kritische Abschnitte bieten Blockierung, aber die API ist zu begrenzt. z.B. Sie können keine CS abrufen, erkennen, dass eine Lesesperre verfügbar ist, aber keine Schreibsperre, und warten, bis der andere Prozess den Lesevorgang beendet hat (denn wenn der andere Prozess den kritischen Abschnitt hat, blockiert er andere Leser, und wenn ja dann blockiert Ihr Prozess nicht, sondern dreht sich, CPU-Zyklen werden gebrannt.)
Sie können jedoch eine Drehsperre verwenden und bei Konflikten auf einen Mutex zurückgreifen. Der kritische Abschnitt ist selbst auf diese Weise implementiert. Ich würde eine vorhandene Implementierung des kritischen Abschnitts nehmen und das PID-Feld mit getrenntem Leser u. Schreiber zählt.
Wenn Sie Vista oder höher als Ziel verwenden können, sollten Sie das integrierte SRWLock verwenden . Sie sind leichtgewichtig wie kritische Abschnitte, vollständig benutzerdefiniert, wenn keine Konflikte auftreten.
Joe Duffys Blog enthält einige Einträge zur Implementierung verschiedener Arten von Nicht-Blocking Leser / Schreiber-Sperren. Diese Schlösser drehen sich, also wären sie nicht angebracht, wenn Sie viel Arbeit machen wollen, während Sie das Schloss halten. Der Code ist C #, sollte aber problemlos auf native portiert werden können.
Sie können eine Lese- / Schreibsperre mit kritischen Abschnitten und Ereignissen implementieren - Sie müssen nur genügend Status beibehalten, um das Ereignis nur zu signalisieren, wenn dies erforderlich ist, um einen unnötigen Kernel-Modus-Aufruf zu vermeiden.
Alte Frage, aber das sollte etwas funktionieren. Es dreht sich nicht bei Konflikten. Leser haben begrenzte zusätzliche Kosten, wenn sie wenig oder keine Konflikte haben, weil SetEvent
träge genannt wird (sehen Sie sich den Bearbeitungsverlauf für eine schwerere Version an, die diese Optimierung nicht hat).
Sie könnten die Kosten für Leser senken, indem Sie ein einzelnes CRITICAL_SECTION
verwenden:
countsLock
wird durch writerLock
in rdlock und rdunlock
rwlock->waitingWriter = FALSE
wird in wrunlock entfernt
wrlocks Körper wird in
geändert %Vor%Allerdings verliert dies an Fairness, daher bevorzuge ich die obige Lösung.
Sehen Sie sich das Buch " Concurrent Programming on Windows " an, das viele verschiedene Referenzbeispiele für den Leser enthält / Writer-Sperren.
Schau dir die spin_rw_mutex von Intels Thread-Building-Blöcken ...
spin_rw_mutex
befindet sich ausschließlich im Benutzerland und verwendet Spin-Wait zum Blockieren
Das ist eine alte Frage, aber vielleicht wird jemand das nützlich finden. Wir haben ein leistungsstarkes Open-Source-Programm RWLock
für Windows entwickelt, das automatisch Vista + SRWLock
Michael erwähnt , falls verfügbar, oder auf eine Userspace-Implementierung zurückgreift.
Als zusätzlichen Bonus gibt es vier verschiedene "Geschmacksrichtungen" (obwohl Sie sich an die Basis halten können, die auch die schnellste ist), die jeweils mehr Synchronisierungsoptionen bietet. Es beginnt mit der Basis RWLock()
, die nicht reentrant ist, beschränkt auf Einzelprozesssynchronisation, und kein Vertauschen von Lese- / Schreibsperren zu einem vollwertigen prozessübergreifenden IPC RWLock mit Wiedereinstiegsunterstützung und Lese- / Schreibzugriff Höhe.
Wie bereits erwähnt, werden sie dynamisch zu den schlanken Lese- / Schreibsperren von Vista + ausgewechselt, um die bestmögliche Leistung zu erzielen, aber Sie müssen sich darüber keine Gedanken machen, da sie auf eine vollständig kompatible Implementierung unter Windows zurückgreift XP und seine Art.
Wenn Sie bereits von einer Lösung wissen, dass only Mutexe verwendet, sollten Sie sie ändern können, um stattdessen kritische Abschnitte zu verwenden.
Wir rollten unsere eigenen mit zwei kritischen Abschnitten und einigen Zählern. Es passt zu unseren Bedürfnissen - wir haben eine sehr niedrige Autorenzahl, Autoren haben Vorrang vor Lesern usw. Ich bin nicht in der Lage, unsere zu veröffentlichen, kann aber sagen, dass es ohne Mutexe und Semaphoren möglich ist.
Schauen Sie sich meine Implementierung hier an:
VRWLock ist eine C ++ - Klasse, die die Logik für einzelne Schreiber - mehrere Leser implementiert.
Sehen Sie sich auch das Testprojekt TestLock.sln an.
UPD. Unten ist der einfache Code für Leser und Schreiber:
%Vor%Die VRWLock-Klasse unterstützt Spin Count und Thread-spezifische Referenzzählung, die es ermöglicht, Sperren von abgeschlossenen Threads freizugeben.
Ich habe den folgenden Code nur mit kritischen Abschnitten geschrieben.
%Vor%Um eine Warteschleife durchzuführen, kommentieren Sie die Zeilen mit Sleep (0).
Tags und Links c++ multithreading winapi critical-section