Begriff
Cache Coherency
Warum wichtig?
Dieser Begriff ist ein Knoten im SengakujiWorks-Wissensnetz. Nutze Level 0 für die erste Einordnung, Level 1 für Praxis, Level 2 für technische Struktur und Level 3 für Grenzen, Fallstricke und Expertenkontext.
Du hast 2 CPUs. Beide haben einen eigenen Cache (L1).
Im RAM steht X = 0.
CPU A lädt X, rechnet X = 1. Das steht jetzt in Cache A.
CPU B lädt X. Was sieht sie?
- Ohne Kohärenz: Sie sieht
0(aus dem RAM). Falsch! - Mit Cache Coherency: Die Hardware sorgt magisch dafür, dass CPU B erfährt: "Achtung, X wurde geändert!". Entweder CPU A schreibt es sofort in den RAM (Write-Through) oder signalisiert B "Dein Wert ist ungültig" (Invalidate). Das passiert in Hardware (MESI Protokoll). Ohne das wäre Multithreading unmöglich.
Merksatz: Ein Mechanismus in Mehrprozessorsystemen, der sicherstellt, dass alle Prozessoren eine konsistente Sicht auf den gemeinsamen Arbeitsspeicher haben, auch wenn Daten in lokalen Caches zwischengespeichert und geändert werden.
Als Programmierer verlässt du dich darauf. Aber es kostest Performance. False Sharing: Wenn zwei Variablen (A und B) nebeneinander im Speicher liegen (gleiche Cache Line). CPU 1 schreibt A. CPU 2 schreibt B. Sie zwingen sich gegenseitig ständig zum Cache-Update ("Ping-Pong"). Obwohl sie logisch nichts teilen! Lösung: Padding (Platzhalter zwischen Variablen), damit sie auf getrennten Cache Lines liegen.
1. MESI Protokoll
Jede Cache Line hat einen Zustand:
- M (Modified): Nur ich habe es, und ich habe es geändert (Dirty).
- E (Exclusive): Nur ich habe es, es ist sauber (gleich RAM).
- S (Shared): Andere haben es auch, es ist sauber.
- I (Invalid): Mein Wert ist Müll. Wenn CPU A schreibt, muss sie erst "Ownership" holen (alle anderen auf I setzen). Das geht über den Bus.
2. Directory-based Coherence
Bei 64 Cores kann man nicht alle anschreien ("Broadcast"), wenn man was ändert. Man nutzt ein "Directory" (Verzeichnis), das weiß, wer welche Cache Line hat. Man sendet die Nachricht nur an die Besitzer. Skaliert besser für NUMA-Systeme.
1. Store Buffers & Memory Barriers
In der Realität ist Cache Coherency noch komplizierter. Damit die CPU nicht auf den Bus warten muss (wenn sie "Ownership" anfordert), nutzt sie Store Buffers. Die CPU schreibt den Wert in einen Puffer und rechnet weiter. Der Puffer schreibt es "irgendwann" in den Cache. Problem: Ein anderer Kern sieht den neuen Wert erst verzögert. Hier kommen Memory Barriers (Fences) ins Spiel. Sie zwingen die CPU, alle Store Buffers zu leeren, bevor der nächste Befehl ausgeführt wird. Ohne diese Barrieren würden Lock-freie Algorithmen (wie in High-Frequency Trading) sofort kaputtgehen, da die Reihenfolge der Schreibvorgänge durcheinandergerät (Memory Reordering).
2. MOESI & MESIF Protokolle
Das klassische MESI hat Schwächen. Wenn CPU B den Wert von CPU A lesen will, muss A ihn erst in den RAM schreiben und B lädt ihn von dort. Modernere Protokolle wie MOESI (AMD) oder MESIF (Intel) fügen Zustände hinzu:
- O (Owned): CPU A kann den Wert direkt an CPU B senden, ohne den RAM zu nutzen. A bleibt aber verantwortlich für das spätere Schreiben in den RAM.
- F (Forward): Bei Shared-Werten wird eine CPU als "Sprecher" bestimmt, um Bus-Traffic zu reduzieren. Diese Optimierungen sind der Grund, warum moderne Server mit 128 Kernen überhaupt noch skalieren.
3. Hardware-Transactional Memory (HTM)
Einige CPUs (Intel TSX) versuchten, Cache Coherency als Basis für Transaktionen zu nutzen. Anstatt mühsam Locks zu programmieren, sagt man der CPU: "Versuch diesen Block atomar auszuführen." Die CPU nutzt die Cache-Kohärenz-Logik, um zu prüfen: "Hat währenddessen jemand anderes auf meine Daten zugegriffen?". Wenn ja -> Rollback. Wenn nein -> Commit. Wegen technischer Bugs (Side-Channel Angriffe) wurde dies in vielen CPUs wieder deaktiviert, bleibt aber ein heiliger Gral des Computer-Designs.
Quick-Check
Volatile (Java)?
Cache Coherency garantiert, dass der Cache konsistent ist.volatilegarantiert zusätzlich Sichtbarkeit im Programmiermodell (Memory Model) und verhindert Reordering durch den Compiler/CPU.GPU?
GPUs haben oft KEINE Cache Coherency zwischen den Cores (oder nur sehe eingeschränkt). Deshalb müssen Grafik-Shader so geschrieben sein, dass sie nicht gesharten Speicher gleichzeitig beschreiben.Teuer?
Ja. Cache-Kohärenz-Verkehr verbraucht viel Bandbreite. Deshalb skalieren Systeme nicht linear (100 CPUs sind nicht 100x schneller).