Shared\Flag
OxPHP\Shared\Flag — це атомарне булеве значення на рівні всього процесу, булевий близнюк Shared\Atomic. Кожна операція неблокувальна (lock-free): два воркери, що одночасно перемикають прапорець, не можуть побачити проміжного стану.
Огляд
- Атомарний bool. Один біт стану з операціями
load/store/swap/compareAndSet. - Явне впорядкування пам’яті. Кожна операція приймає необов’язковий параметр
Ordering, за замовчуваннямSeqCst, — так само, як уShared\Atomic. - Без блокувань. Кожна зміна — це одна атомарна інструкція процесора. Безпечно за високої конкуренції.
- Спільний доступ. Екземпляри зберігаються в реєстрі, їх можна класти в
Shared\Map, передавати через захопленняuseтощо.
Довідник API
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
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
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
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
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 — потрібні сторінки він прочитає сам.
Використай OxPHP Shared Flag у моєму коді замість перемикача режиму обслуговування чи запобіжника, який я зараз тримаю у змінній оточення або конфігураційному файлі. Прочитай сторінку `shared-state/shared-flag` через MCP-сервер документації OxPHP.
Знайди цей перемикач у репозиторії та покажи мені заміну на Flag, а також те єдине місце виклику, де має бути `compareAndSet`, а не безумовний `store`.Пов’язане
- Спільний стан — огляд і ментальна модель.
- Shared\Atomic — int64-близнюк із тією самою моделлю впорядкування.
- Shared\Counter — коли потрібно більше, ніж увімкнено/вимкнено.
- Shared\Once — коли одноразово обчислене значення багатше за bool.
- Shared\Mutex — коли перемикання прапорця має фіксуватися разом з іншим станом.