====== Lyx OS – Sync-Primitive ====== Diese Seite dokumentiert die Synchronisations-Primitive in ''kernel/sync.lyx'' (WP9): Spinlock, Mutex und Semaphor. Alle Primitive sind für Kernel-Code (Ring-0) konzipiert. → [[lyxos:architektur|Architektur]] · [[lyxos:smp|SMP & Tasks]] · [[lyxos:kernel|Kernel-Interna]] ---- ===== 1. Überblick ===== ''sync.lyx'' stellt drei Arten von Synchronisations-Primitiven bereit: ^ Primitiv ^ Einsatz ^ Implementierung ^ | Spinlock | Kurze kritische Abschnitte, Unterbrechungsschutz | Aktives Warten via ''LOCK XCHG'' (''vmm_op8'') | | Mutex | Längere Abschnitte, schlafen erlaubt | Kernel-verwaltet via ''vmm_op9–11'', optionaler Timeout | | Semaphor | Producer-Consumer, Ressourcenzähler | Kernel-verwaltet via ''vmm_op12–14'', Zähler konfigurierbar | ---- ===== 2. Spinlock ===== Ein Spinlock ist ein einfacher busy-wait-Lock. Er eignet sich für sehr kurze kritische Abschnitte, z.B. Schutz von Print-Ausgaben über mehrere Prozessoren. // Adresse des system-weiten Print-Spinlocks holen (einmal, beim Start): var print_lock: int64 := GetPrintSpinlockAddr(); // → vmm_op15 // Kritischen Abschnitt schützen: SpinlockAcquire(print_lock); PrintLn("Atomar ausgegeben"); SpinlockRelease(print_lock); **Eigenschaften:** * ''SpinlockAcquire(lock_ptr)'' — schreibt 1 in die Lock-Variable via ''LOCK XCHG''; dreht sich so lange, bis der alte Wert 0 war * ''SpinlockRelease(lock_ptr)'' — schreibt 0 (''poke64(ptr, 0)'') * Kein Schlaf, kein Scheduling-Eingriff — nur für sehr kurze Abschnitte geeignet * ''GetPrintSpinlockAddr()'' gibt eine kernel-weite Lock-Adresse zurück, die alle Kernel-Threads und APs gemeinsam nutzen ---- ===== 3. Mutex ===== Ein Mutex ist ein schläfender Lock. Der Kernel schläft wartende Threads ein und weckt sie nach dem Unlock wieder auf. // Mutex anlegen: var mx: int64 := MutexCreate(MUTEX_PLAIN); // MUTEX_PLAIN=0, MUTEX_RECURSIVE=1 // Lock mit unbegrenztem Timeout: var err: int64 := MutexLock(mx); // Lock mit Timeout (Nanosekunden): var err: int64 := MutexLockTimeout(mx, 1000000); // 1 ms // Unlock: MutexUnlock(mx); ^ Konstante ^ Wert ^ Bedeutung ^ | MUTEX_PLAIN | 0 | Normaler Mutex — kein rekursives Lock erlaubt | | MUTEX_RECURSIVE | 1 | Rekursiver Mutex — selber Thread darf mehrfach locken | **Hinweis:** ''MutexCreate'' gibt eine Integer-ID zurück (kein Zeiger). Die eigentliche Mutex-Struktur liegt im Kernel-Verwaltungsbereich und ist nicht direkt zugänglich. ---- ===== 4. Semaphor ===== Ein Semaphor verwaltet einen ganzzahligen Zähler. ''SemWait'' dekrementiert (und schläft, wenn Zähler = 0). ''SemPost'' inkrementiert und weckt einen wartenden Thread auf. // Semaphor anlegen (initial count = 2): var sem: int64 := SemCreate(2, 0); // flags: 0 = anonym, SEM_NAMED=1 = benannt SemWait(sem); // Zähler −1; schläft wenn Zähler = 0 SemWait(sem); // nochmal −1 SemPost(sem); // Zähler +1; weckt ggf. wartenden Thread auf **Typischer Einsatz — Producer/Consumer:** var sem_full: int64 := SemCreate(0, 0); // Elemente im Puffer var sem_empty: int64 := SemCreate(8, 0); // Freie Plätze (Puffergröße = 8) // Producer: SemWait(sem_empty); // ... in Puffer schreiben ... SemPost(sem_full); // Consumer: SemWait(sem_full); // ... aus Puffer lesen ... SemPost(sem_empty); ---- ===== 5. Wann welches Primitiv? ===== ^ Situation ^ Empfehlung ^ | Print-Ausgaben serialisieren (Multi-Core) | ''SpinlockAcquire'' / ''Release'' auf ''GetPrintSpinlockAddr()'' | | Gemeinsame Datenstruktur schützen (kurz) | Spinlock | | Gemeinsame Datenstruktur schützen (länger) | Mutex mit ''MUTEX_PLAIN'' | | Initialisierung einmalig sicherstellen | Mutex: vor Init locken, danach unlocked lassen | | Ressourcenzähler (n Slots verfügbar) | Semaphor | | Producer-Consumer-Puffer | Zwei Semaphore (''sem_full'' + ''sem_empty'') | Letzte Aktualisierung: 2026-06-13