# AMPHP v3 — Sync Primitives (Mutex, Semaphore, Barrier, Parcel) Fibers share memory. Protect shared mutable state with sync primitives. --- ## LocalMutex — exclusive lock ```php acquire(); try { $current = $counter; delay(0); // yield — other fibers try to run, but they'll block on acquire() $counter = $current + 1; } finally { $lock->release(); // ALWAYS in finally } }); } await($futures); echo $counter; // 10 — consistent thanks to mutex ``` --- ## synchronized() — cleaner alternative to try/finally ```php async( fn() => synchronized($mutex, function () use (&$log, $i): void { $log[] = "enter-$i"; $log[] = "exit-$i"; }) ), range(1, 3)); await($futures); // $log entries are never interleaved ``` --- ## LocalSemaphore — limit concurrency ```php acquire(); try { return $client->request(new \Amp\Http\Client\Request($url))->getBody()->buffer(); } finally { $lock->release(); } }); }, $urls); $bodies = await($futures); ``` --- ## LocalParcel — atomic read-modify-write ```php async(fn() => $parcel->synchronized(fn(int $v) => $v + 1)), range(1, 10), ); await($futures); echo $parcel->unwrap(); // 10 — atomic, always consistent ``` > **Important**: the closure passed to `synchronized()` receives the **current value** and > **must return the new value** to store it. Modifying in-place won't work. --- ## Barrier — rendezvous point for N fibers ```php async(function () use ($barrier, &$log, $i): void { delay($i * 0.01); // stagger $log[] = "arrived-$i"; $barrier->arrive(); // non-blocking — decrements counter }), [1, 2, 3]); $barrier->await(); // suspends until all 3 have called arrive() $log[] = 'all-arrived'; await($futures); ``` --- ## LocalKeyedMutex — per-key locking ```php acquire('user:1'); try { delay(0.02); } finally { $lock->release(); } }), async(function () use ($mutex): void { $lock = $mutex->acquire('user:1'); // same key — waits for the lock above try { /* runs after user:1 lock released */ } finally { $lock->release(); } }), async(function () use ($mutex): void { $lock = $mutex->acquire('user:2'); // different key — runs immediately try { /* concurrent with user:1 */ } finally { $lock->release(); } }), ]; await($futures); ``` --- ## RateLimitingSemaphore — throttle over time ```php 0. $inner = new LocalSemaphore(5); // 5 concurrent slots $rateLimited = new RateLimitingSemaphore($inner, 1.0); // each slot reusable once per second $futures = []; for ($i = 1; $i <= 10; $i++) { $futures[] = async(function () use ($rateLimited, $i): int { $lock = $rateLimited->acquire(); try { return $i * 10; } finally { $lock->release(); } }); } $results = await($futures); ```