Shared\Flag

OxPHP\Shared\Flag to atomiczna wartość logiczna obowiązująca w całym procesie — logiczny odpowiednik Shared\Atomic. Każda operacja jest bezblokadowa; dwa workery przełączające flagę współbieżnie nie mogą zaobserwować stanu pośredniego.

Przegląd

  • Atomiczny bool. Pojedynczy bit stanu z operacjami load / store / swap / compareAndSet.
  • Jawne porządkowanie pamięci. Każda operacja przyjmuje opcjonalny Ordering, domyślnie SeqCst, dokładnie tak jak Shared\Atomic.
  • Bezblokadowa. Wszystkie modyfikacje to pojedyncza operacja atomowa CPU. Bezpieczna przy rywalizacji.
  • Współdzielona. Instancje żyją w rejestrze i można je przechowywać wewnątrz Shared\Map, przekazywać przez przechwycenia use itd.

Dokumentacja API

php
namespace OxPHP\Shared; final class Flag implements Shareable { public function __construct(bool $initial = false); public function load(Ordering $order = Ordering::SeqCst): bool; // Relaxed | Acquire | SeqCst public function store(bool $value, Ordering $order = Ordering::SeqCst): void; // Relaxed | Release | SeqCst public function swap(bool $value, Ordering $order = Ordering::SeqCst): bool; // any ordering; returns previous public function compareAndSet( bool $expect, bool $new, Ordering $success = Ordering::SeqCst, Ordering $failure = Ordering::SeqCst, // Relaxed | Acquire | SeqCst ): bool; public function id(): int; }
Metoda Zwraca Zastosowanie
load bieżącą Czysty odczyt.
store void Bezwarunkowe ustawienie na jawną wartość.
swap poprzednią Ustawia jawną wartość; wartość zwrotna mówi, czy ją zmieniłeś. swap(true) to test-and-set („czy wygrałem?").
compareAndSet zamieniono? Jednorazowa inicjalizacja: powiedzie się tylko wtedy, gdy flaga miała oczekiwaną wartość.

Przykłady

Wyłącznik awaryjny

php
<?php use OxPHP\Shared\Flag; $maintenance = new Flag(); // In a request handler if ($maintenance->load()) { http_response_code(503); header('Retry-After: 60'); echo 'under maintenance'; return; } // In an admin endpoint $maintenance->store(true); // enable $maintenance->store(false); // disable

Zwycięzca jednorazowej inicjalizacji

php
<?php use OxPHP\Shared\Flag; $migrated = new Flag(); if ($migrated->compareAndSet(expect: false, new: true)) { // First worker to arrive wins — run the migration once. runSchemaMigration(); } else { // Someone else already ran it. }

Zadziałanie bezpiecznika

php
<?php use OxPHP\Shared\Flag; $tripped = new Flag(); try { callDownstream(); } catch (DownstreamFailedException $e) { $wasAlreadyTripped = $tripped->swap(true); // set true, learn the prior state if (!$wasAlreadyTripped) { alertOncall($e); // fire alert only on first trip } throw $e; }

Aby zbudować kompletny bezpiecznik, zwykle będziesz potrzebować Shared\Counter dla okna błędów oraz Shared\Flag dla stanu zadziałania — zresetuj flagę przez store(false), gdy okno ostygnie.

Opublikuj ładunek, a potem zasygnalizuj tańszym porządkowaniem

php
<?php use OxPHP\Shared\Flag; use OxPHP\Shared\Map; use OxPHP\Shared\Ordering; $ready = new Flag(); $config = new Map(); // Producer: write the payload, then publish with Release. $config->set('dsn', $dsn); $ready->store(true, Ordering::Release); // Consumer: an Acquire load that observes `true` also observes the payload. if ($ready->load(Ordering::Acquire)) { $dsn = $config->get('dsn'); }

Semantyka i pułapki

swap zwraca poprzednią wartość, co jest najbardziej użytecznym wynikiem: „czy coś zmieniłem?" to $prev !== $new, a swap(true) to kanoniczny test-and-set. store zwraca void; jeśli potrzebujesz poprzedniej wartości, użyj swap.

compareAndSet to sposób na wyrażenie „pierwszy wygrywa". Zwykłe store(true) zawsze się powiedzie, więc nie potrafi wyrazić „nie nadpisuj, jeśli już ustawione".

Porządkowanie pamięci

Porządkowanie pamięci odpowiada Shared\Atomic. load odrzuca Release/AcqRel, store odrzuca Acquire/AcqRel, a $failure w compareAndSet odrzuca Release/AcqRel — każde z nich zgłasza InvalidOrderingException. Domyślne SeqCst jest zawsze bezpieczne.

Brak oczekiwania

Flaga nie blokuje. Jeśli musisz zaczekać na przejście, połącz ją z Shared\Channel lub użyj Shared\Once.

Wyjątki

Wyjątek Zgłaszany przez
StaleHandleException Dowolną metodę na uchwycie, którego wpis w rejestrze usunięto.
UninitializedException id() na obiekcie opakowującym, który nie zakończył __construct.
InvalidOrderingException Ordering niedozwolone dla danej operacji (patrz wyżej).

Obserwowalność

Zobacz Obserwowalność stanu współdzielonego. Szybkie odniesienia:

  • GET /__ox_shared/entry?id=N udostępnia { value: true|false, type: "Flag" }.
  • Miernik Prometheus oxphp_shared_flag_value{flag_id="…"} (0 lub 1).
  • Metryki obejmujące cały rejestr uwzględniają Flag dzięki etykiecie type="Flag".

Kiedy nie używać

  • Logika wielostanowa. Flaga jest dwuwartościowa. Jeśli potrzebujesz stanów idle/busy/done lub dowolnej maszyny trójstanowej, sięgnij po Shared\Counter (użyj całkowitoliczbowych wartości enum) albo Shared\Mutex nad tablicą przypominającą enum.
  • Oczekiwanie na przejście. Flagi nie blokują. Połącz z Shared\Channel (albo z Shared\Counter, który odpytujesz przez compareAndSet), gdy worker ma czekać, aż flaga się przełączy.
  • Zliczanie zdarzeń. Flaga nie jest licznikiem. Do zliczania używaj Shared\Counter.
  • Stan całkowitoliczbowy. Jeśli przełącznik jest w istocie małą liczbą całkowitą, użyj bezpośrednio Shared\Atomic.

Powiązane

  • Stan współdzielony — przegląd i model myślowy.
  • Shared\Atomic — odpowiednik int64, ten sam model porządkowania.
  • Shared\Counter — gdy potrzebujesz czegoś więcej niż włącz/wyłącz.
  • Shared\Once — gdy wartość obliczana raz jest bogatsza niż bool.
  • Shared\Mutex — gdy przełączenie flagi musi zostać zatwierdzone wspólnie z innym stanem.