Start · Sprachen · PHP · Referenz · Swoole\Atomic

Swoole\Atomic

Klasse

Bietet atomare Ganzzahl-Zähleroperationen, die sicher über mehrere Prozesse und Coroutinen hinweg genutzt werden können.

seit PHP 1.8.0 Kategorie: misc

Signatur

class Swoole\Atomic

Beschreibung

Swoole\Atomic implementiert einen atomaren Zähler auf Basis von Shared Memory und CPU-Atominstruktionen (CAS). Dadurch können mehrere Worker-Prozesse oder Threads denselben Zähler lesen und schreiben, ohne dass es zu Race Conditions kommt – ganz ohne zusätzliche Mutexe oder Locks.

Ein typischer Anwendungsfall ist die Verwaltung von Request-Zählern, Verbindungsstatistiken oder einfachen Flags in einem Swoole-Server, der mit mehreren Worker-Prozessen betrieben wird. Da der Wert im Shared Memory liegt, ist er nach dem Erstellen des Swoole\Server (d. h. vor dem Start) zu initialisieren, damit alle Kindprozesse Zugriff erhalten.

Die unterstützten Operationen umfassen Inkrementieren (add), Dekrementieren (sub), atomares Compare-and-Swap (cmpset) sowie direktes Lesen (get) und Setzen (set). Alle diese Methoden sind thread- und prozess-sicher.

Wichtig: Swoole\Atomic arbeitet ausschließlich mit vorzeichenlosen 32-Bit-Ganzzahlen (uint32, Wertebereich 0–4 294 967 295). Für 64-Bit-Werte steht Swoole\Atomic\Long zur Verfügung.

Parameter

Name Typ Default Beschreibung
$init_value int 0 Initialer Wert des atomaren Zählers. Muss im Bereich einer vorzeichenlosen 32-Bit-Ganzzahl (0–4 294 967 295) liegen.

Beispiele

Einfacher atomarer Zähler in einem Swoole-Server

<?php
// Atomic VOR dem Serverstart erstellen, damit alle Worker-Prozesse
// auf denselben Shared-Memory-Bereich zugreifen können.
$counter = new Swoole\Atomic(0);

$server = new Swoole\Http\Server('0.0.0.0', 9501);
$server->set(['worker_num' => 4]);

$server->on('request', function ($request, $response) use ($counter) {
    // Atomares Inkrementieren – sicher über alle Worker hinweg
    $total = $counter->add(1);
    $response->end("Anfrage Nr. {$total}\n");
});

$server->start();

Compare-and-Swap (CAS) für bedingtes Setzen

<?php
$flag = new Swoole\Atomic(0);

// Nur wenn der aktuelle Wert 0 ist, wird er auf 1 gesetzt (einmaliges Init-Flag)
if ($flag->cmpset(0, 1)) {
    echo "Initialisierung erfolgreich – dieser Block läuft nur einmal.\n";
} else {
    echo "Bereits initialisiert.\n";
}

// Zweiter Aufruf schlägt fehl, da der Wert nun 1 ist
if ($flag->cmpset(0, 1)) {
    echo "Nochmals initialisiert.\n";
} else {
    echo "CAS fehlgeschlagen – Wert war nicht 0.\n";
}

echo 'Aktueller Wert: ' . $flag->get() . "\n";
Initialisierung erfolgreich – dieser Block läuft nur einmal. CAS fehlgeschlagen – Wert war nicht 0. Aktueller Wert: 1

Wert lesen, setzen und dekrementieren

<?php
$atomic = new Swoole\Atomic(10);

echo 'Start: ' . $atomic->get() . "\n";   // 10
$atomic->add(5);                            // 10 + 5 = 15
echo 'Nach add(5): ' . $atomic->get() . "\n";

$atomic->sub(3);                            // 15 - 3 = 12
echo 'Nach sub(3): ' . $atomic->get() . "\n";

$atomic->set(0);                            // Zurücksetzen
echo 'Nach set(0): ' . $atomic->get() . "\n";
Start: 10 Nach add(5): 15 Nach sub(3): 12 Nach set(0): 0

// Wichtig · Fallstricke

Initialisierungszeitpunkt: Swoole\Atomic-Objekte müssen vor dem Aufruf von $server->start() erzeugt werden. Werden sie erst innerhalb eines Callback-Handlers erstellt, existieren sie nur im Speicher des jeweiligen Worker-Prozesses und sind nicht prozessübergreifend sichtbar.

Wertebereich: Der Zähler ist ein vorzeichenloser 32-Bit-Integer. Ein Unterschreiten von 0 führt zu einem Überlauf (Wraparound auf 4 294 967 295). Für Zähler, die negative Werte oder Werte > 4 294 967 295 erfordern, ist Swoole\Atomic\Long (vorzeichenbehaftet, 64-Bit) zu verwenden.

Keine Sperren nötig: Die Operationen add, sub, cmpset und set sind atomar und benötigen weder Mutex noch Semaphor. Der Einsatz zusätzlicher Synchronisationsmechanismen ist daher nicht erforderlich und würde die Performance verschlechtern.