Shared\Flag
OxPHP\Shared\Flag はプロセス全体で共有されるアトミックなブール値であり、Shared\Atomic の bool 版です。すべての操作はロックフリーで、2 つのワーカーが同時にフラグを反転させても、中間状態が観測されることはありません。
概要
- アトミックな bool。
load/store/swap/compareAndSetを備えた 1 ビットの状態です。 - 明示的なメモリオーダリング。 すべての操作は省略可能な
Orderingを受け取り、デフォルトはSeqCstです。Shared\Atomicとまったく同じです。 - ロックフリー。 すべての変更は単一の CPU アトミック命令です。競合下でも安全です。
- 共有可能。 インスタンスはレジストリ内に存在し、
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 は「最初の 1 つが勝つ」を表現する方法です。 単なる store(true) は常に成功するため、「すでに設定済みなら上書きしない」を表現できません。
メモリオーダリングは Shared\Atomic と同じです。load は Release/AcqRel を拒否し、store は Acquire/AcqRel を拒否し、compareAndSet の $failure は Release/AcqRel を拒否します。いずれの場合も InvalidOrderingException を送出します。デフォルトの SeqCst は常に安全です。
Flag はブロックしません。状態遷移を待つ必要がある場合は、Shared\Channel と組み合わせるか、Shared\Once を使ってください。
例外
| 例外 | 発生元 |
|---|---|
StaleHandleException |
レジストリエントリが破棄されたハンドルに対するあらゆるメソッド。 |
UninitializedException |
__construct が完了していないラッパーに対する id()。 |
InvalidOrderingException |
その操作で許可されていない Ordering(上記参照)。 |
可観測性
Shared の可観測性 を参照してください。クイックリファレンス:
GET /__ox_shared/entry?id=Nは{ value: true|false, type: "Flag" }を公開します。- Prometheus の
oxphp_shared_flag_value{flag_id="…"}ゲージ(0 または 1)。 - レジストリ全体のメトリクスは
type="Flag"ラベルを通じて Flag をカバーします。
使うべきでないケース
- 多状態のロジック。 Flag は 2 値です。idle/busy/done のような 3 状態のステートマシンが必要な場合は、
Shared\Counter(整数の列挙値を使う)や、列挙型のような配列に対するShared\Mutexを検討してください。 - 状態遷移の待機。 Flag はブロックしません。ワーカーがフラグの反転を待つ必要がある場合は、
Shared\Channel(またはcompareAndSetでポーリングするShared\Counter)と組み合わせてください。 - イベントのカウント。 Flag はカウンターではありません。集計には
Shared\Counterを使ってください。 - 整数の状態。 スイッチが実際には小さな整数である場合は、
Shared\Atomicを直接使ってください。
関連
- Shared State — 概要とメンタルモデル。
- Shared\Atomic — int64 版の双子。同じオーダリングモデルです。
- Shared\Counter — オン/オフ以上のものが必要なとき。
- Shared\Once — 一度だけ計算される値が bool より複雑なとき。
- Shared\Mutex — フラグの反転が他の状態と同時にコミットされる必要があるとき。