Wenn Sie nur in der Lage sein müssen enable = true
einzustellen, dann gibt Ihnen stdatomic.h
mit release/acquire bestellen genau das, wonach Sie fragen. (In x86-asm haben normale Stores/Loads eine Semantik zum Freigeben/Akquirieren, also ist das Blockieren der Neuordnung der Kompilierungszeit irgendwie ausreichend. Aber der richtige Weg dazu ist atomic
, nicht volatile
.)
Aber wenn Sie in der Lage sein möchten, enable = false
zu sperren, um Leser erneut zu sperren, während Sie es ändern, dann benötigen Sie ein komplizierteres Update-Muster. Entweder erfinden Sie einen Mutex manuell mit Atomics neu (schlechte Idee; verwenden Sie stattdessen einen Standard-Bibliotheks-Mutex) oder machen Sie etwas, das einen latenzfreien Lesezugriff durch mehrere Leser zulässt, wenn kein Schreiber mitten in einem Update ist.
Entweder RCU a oder seqlock könnte hier gut sein.
Für einen Seqlock haben Sie anstelle eines enable = true/false-Flags eine Sequenznummer. Ein Leser kann einen "zerrissenen" Schreibvorgang erkennen, indem er die Sequenznummer vor und nach dem Lesen der anderen Mitglieder überprüft. (Aber dann alle Mitglieder müssen atomic
, mit mindestens mo_relaxed
, sonst ist es Datenrennen undefiniertes Verhalten nur aus dem Lesen sie in C, auch wenn Sie den Wert zu verwerfen.Sie benötigen auch ausreichende Reihenfolge auf die Lasten, die den Zähler überprüfen wahrscheinlich erwerben Sie auf der ersten, dann erwerben Sie auf der shared_struct->b
Last, um sicherzustellen, dass die zweite Last der Sequenznummer nach ihm bestellt wird. (acquire
ist nur eine Einweg-Barriere: eine Übernahme Last nach einer entspannten Last würde Ihnen nicht geben Was Sie brauchen.)
RCU macht die Leser immer komplett wartefrei, sie dereferenzieren nur einen Zeiger auf die aktuell gültige Struktur.Wiederholungen sind so einfach wie atomare Ersetzen eines Zeigers.Recycling alten Strukturen ist, wo es kompliziert wird: Sie müssen sicher sein, dass jeder Leser-Thread einen Mem-Block gelesen hat oder bevor Sie es wiederverwenden.
einfach enable = false
Einstellung, bevor Sie die anderen Strukturkomponenten Ändern stoppt nicht einen Leser von enable == true
zu sehen und dann inkonsistent/teilweise aktualisierten Werten für die anderen Mitglieder zu sehen, während ein Schriftsteller sie ändern. Wenn Sie dies nicht tun müssen, aber immer nur neue Objekte für den Zugriff durch andere Threads freigeben müssen, ist die von Ihnen beschriebene Sequenz in Ordnung mit atomic_store_explicit(&foo->enable, true, memory_order_release)
.
Das ist * gar nicht * was volatil ist für. Wenn es ein atomares Flag gibt, sollten Sie C11 verwenden '' –
Ich weiß - es ist ein "Nebenprodukt", dass flüchtige Zugriffe nicht neu geordnet werden. – filo
@AnttiHaapala Was hat der atomare Zugriff mit der Neuordnung von Anweisungen zu tun? – Lundin