Shared\Flag

OxPHP\Shared\Flag — це атомарне булеве значення на рівні всього процесу, булевий близнюк Shared\Atomic. Кожна операція неблокувальна (lock-free): два воркери, що одночасно перемикають прапорець, не можуть побачити проміжного стану.

Огляд

  • Атомарний bool. Один біт стану з операціями load / store / swap / compareAndSet.
  • Явне впорядкування пам’яті. Кожна операція приймає необов’язковий параметр Ordering, за замовчуванням SeqCst, — так само, як у Shared\Atomic.
  • Без блокувань. Кожна зміна — це одна атомарна інструкція процесора. Безпечно за високої конкуренції.
  • Спільний доступ. Екземпляри зберігаються в реєстрі, їх можна класти в Shared\Map, передавати через захоплення use тощо.

Довідник 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; }
Метод Повертає Коли використовувати
load поточне Просте читання.
store void Безумовно встановити явне значення.
swap попереднє Встановити явне значення; результат показує, чи ви його змінили. swap(true) — це test-and-set («чи я переміг?»).
compareAndSet чи замінено Одноразова ініціалізація: успіх лише тоді, коли прапорець мав очікуване значення.

Приклади

Аварійний вимикач

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

Переможець одноразової ініціалізації

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. }

Спрацювання запобіжника

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; }

Для повноцінного запобіжника зазвичай знадобляться Shared\Counter для вікна збоїв і Shared\Flag для стану спрацювання — скидайте прапорець через store(false), щойно вікно охолоне.

Опублікувати дані, потім подати сигнал із дешевшим упорядкуванням

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'); }

Семантика й підводні камені

swap повертає попереднє значення, і це найкорисніший варіант результату: «чи змінив я щось?» — це $prev !== $new, а swap(true) — канонічний test-and-set. store повертає void; якщо вам потрібне попереднє значення, використовуйте swap.

compareAndSet — це спосіб виразити «перший виграє». Звичайний store(true) завжди успішний, тож ним неможливо виразити «не перезаписувати, якщо вже встановлено».

Упорядкування пам’яті

Упорядкування пам’яті таке саме, як у Shared\Atomic. load відхиляє Release/AcqRel, store відхиляє Acquire/AcqRel, а параметр $failure у compareAndSet відхиляє Release/AcqRel — у кожному разі викидається InvalidOrderingException. Типове SeqCst завжди безпечне.

Без очікування

Flag не блокує. Якщо потрібно дочекатися зміни стану, поєднайте його з Shared\Channel або використовуйте Shared\Once.

Винятки

Виняток Коли виникає
StaleHandleException Будь-який метод дескриптора, чий запис у реєстрі було витіснено.
UninitializedException id() на обгортці, яка ще не завершила __construct.
InvalidOrderingException Ordering, не дозволене для цієї операції (див. вище).

Спостережуваність

Див. Спостережуваність спільного стану. Коротко:

  • GET /__ox_shared/entry?id=N повертає { value: true|false, type: "Flag" }.
  • Gauge-метрика Prometheus oxphp_shared_flag_value{flag_id="…"} (0 або 1).
  • Метрики всього реєстру охоплюють Flag через мітку type="Flag".

Коли не використовувати

  • Логіка з кількома станами. Flag має лише два значення. Якщо потрібні стани idle/busy/done чи будь-який автомат із трьома станами, беріть Shared\Counter (з цілочисельними значеннями-переліком) або Shared\Mutex над масивом, схожим на enum.
  • Очікування зміни стану. Прапорці не блокують. Поєднуйте з Shared\Channel (або з Shared\Counter, який ви опитуєте через compareAndSet), коли воркер має чекати, доки прапорець перемкнеться.
  • Підрахунок подій. Flag — не лічильник. Для підрахунків використовуйте Shared\Counter.
  • Цілочисельний стан. Якщо перемикач насправді є невеликим цілим числом, використовуйте безпосередньо Shared\Atomic.

Промпти для вашого агента

Ці промпти розраховані на агента з підключеним MCP-сервером документації OxPHP — потрібні сторінки він прочитає сам.

prompt
Використай OxPHP Shared Flag у моєму коді замість перемикача режиму обслуговування чи запобіжника, який я зараз тримаю у змінній оточення або конфігураційному файлі. Прочитай сторінку `shared-state/shared-flag` через MCP-сервер документації OxPHP. Знайди цей перемикач у репозиторії та покажи мені заміну на Flag, а також те єдине місце виклику, де має бути `compareAndSet`, а не безумовний `store`.

Пов’язане

  • Спільний стан — огляд і ментальна модель.
  • Shared\Atomic — int64-близнюк із тією самою моделлю впорядкування.
  • Shared\Counter — коли потрібно більше, ніж увімкнено/вимкнено.
  • Shared\Once — коли одноразово обчислене значення багатше за bool.
  • Shared\Mutex — коли перемикання прапорця має фіксуватися разом з іншим станом.