Start · Sprachen · PHP · Referenz · Threaded

Threaded

Klasse

Basisklasse für Objekte, die sicher zwischen mehreren Threads geteilt und synchronisiert werden können (pthreads-Extension).

seit PHP 2.0.0 Kategorie: oop

Signatur

class Threaded implements Collectable, Traversable, Countable, ArrayAccess

Beschreibung

Threaded ist die fundamentale Basisklasse der pthreads-Extension und ermöglicht es, PHP-Objekte thread-sicher zu gestalten. Jede Klasse, die von Threaded erbt, kann gleichzeitig von mehreren Threads gelesen und beschrieben werden, da der interne Mechanismus automatisch eine gegenseitige Sperrung (Mutex) gewährleistet.

Typischerweise wird Threaded nicht direkt instanziiert, sondern dient als Elternklasse für eigene Datencontainer, die zwischen Worker- oder Thread-Instanzen ausgetauscht werden sollen. Über die eingebauten Methoden synchronized(), wait(), notify() und notifyAll() lässt sich die klassische Monitor-Synchronisation realisieren.

Da Threaded das Interface ArrayAccess implementiert, können Eigenschaften eines Threaded-Objekts auch per Array-Notation ($obj['key']) gelesen und geschrieben werden. Die Klasse implementiert außerdem Countable, sodass count() die Anzahl der gespeicherten Eigenschaften liefert.

Hinweis: Die pthreads-Extension ist nur für CLI-SAPI verfügbar und erfordert eine Thread-sichere (ZTS) PHP-Kompilierung. Ab pthreads v3 wurde der Funktionsumfang erheblich geändert; Threaded existiert weiterhin, jedoch ohne direkte Thread-Erzeugung — dafür dienen Thread bzw. Worker.

Beispiele

Gemeinsam genutzter Datenpuffer zwischen Threads

<?php
// Voraussetzung: pthreads-Extension, ZTS-PHP, CLI

class SharedBuffer extends Threaded
{
    public function addItem(string $item): void
    {
        // Threaded-Array wächst automatisch thread-sicher
        $this[] = $item;
    }
}

class Producer extends Thread
{
    public function __construct(private SharedBuffer $buffer) {}

    public function run(): void
    {
        for ($i = 0; $i < 5; $i++) {
            $this->buffer->addItem('Eintrag-' . $i);
            usleep(10000);
        }
    }
}

$buffer   = new SharedBuffer();
$producer = new Producer($buffer);
$producer->start();
$producer->join();

echo 'Elemente im Puffer: ' . count($buffer) . PHP_EOL;
foreach ($buffer as $key => $value) {
    echo $key . ' => ' . $value . PHP_EOL;
}
Elemente im Puffer: 5 0 => Eintrag-0 1 => Eintrag-1 2 => Eintrag-2 3 => Eintrag-3 4 => Eintrag-4

Synchronisierung mit wait() und notify()

<?php
// Klassisches Producer-Consumer-Muster mit Threaded-Synchronisation

class Channel extends Threaded
{
    private bool $ready = false;
    private mixed $data  = null;

    public function send(mixed $value): void
    {
        $this->synchronized(function () use ($value) {
            $this->data  = $value;
            $this->ready = true;
            $this->notify(); // wartenden Consumer aufwecken
        });
    }

    public function receive(): mixed
    {
        return $this->synchronized(function () {
            while (!$this->ready) {
                $this->wait(); // blockiert, bis notify() aufgerufen wird
            }
            $this->ready = false;
            return $this->data;
        });
    }
}

class Consumer extends Thread
{
    public function __construct(private Channel $channel) {}

    public function run(): void
    {
        $value = $this->channel->receive();
        echo 'Consumer erhielt: ' . $value . PHP_EOL;
    }
}

$channel  = new Channel();
$consumer = new Consumer($channel);
$consumer->start();

sleep(1); // Producer wartet kurz
$channel->send('Hallo vom Producer!');
$consumer->join();
Consumer erhielt: Hallo vom Producer!

// Wichtig · Fallstricke

Nur CLI und ZTS: pthreads funktioniert ausschließlich im CLI-SAPI mit einer Thread-sicher kompilierten PHP-Version (Thread Safe, ZTS). In FPM oder Apache-Modulen steht die Extension nicht zur Verfügung.

Objekt-Serialisierung: Werden normale PHP-Objekte als Eigenschaften eines Threaded-Objekts gespeichert, werden sie intern serialisiert. Das Verhalten kann überraschend sein – am sichersten ist es, ausschließlich skalare Werte oder weitere Threaded-Instanzen als Eigenschaften zu verwenden.

Verfügbarkeit: pthreads wird seit PHP 8.x nicht mehr aktiv gepflegt. Für moderne Parallelverarbeitung in PHP empfiehlt sich stattdessen die parallel-Extension oder prozessbasierte Ansätze wie pcntl_fork().

Deadlock-Gefahr: Bei verschachtelten synchronized()-Blöcken oder falscher Reihenfolge von wait()/notify() drohen Deadlocks. Die Synchronisationslogik sollte stets sorgfältig entworfen werden.