Signatur
Beschreibung
sem_acquire() wird verwendet, um exklusiven Zugriff auf eine kritische Sektion in parallelen Prozessen zu erlangen. Ist der Semaphor bereits von einem anderen Prozess belegt, blockiert die Funktion standardmäßig so lange, bis der Semaphor freigegeben wird. Dadurch lassen sich Race Conditions vermeiden, wenn mehrere PHP-Prozesse auf gemeinsame Ressourcen (z. B. Dateien, Shared Memory) zugreifen.
Mit dem optionalen Parameter non_blocking kann verhindert werden, dass der aufrufende Prozess wartet: Wenn der Semaphor belegt ist, gibt die Funktion sofort false zurück, anstatt zu blockieren. Dies ist nützlich, wenn ein Prozess bei nicht verfügbarem Semaphor alternativ handeln soll.
Ein Prozess kann denselben Semaphor mehrfach acquiren. Bei jeder erfolgreichen Anforderung muss am Ende ein entsprechendes sem_release() aufgerufen werden, da sonst andere Prozesse dauerhaft blockiert bleiben. Die maximale Anzahl gleichzeitiger Anforderungen wird beim Erstellen des Semaphors über sem_get() mit dem Parameter max_acquire festgelegt.
Semaphoren sind ein IPC-Mechanismus (Inter-Process Communication) des Betriebssystems und stehen nur unter Unix/Linux zur Verfügung. Unter Windows ist diese Funktion nicht verfügbar.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $semaphore Pflicht | SysvSemaphore | Ein Semaphor-Handle, das zuvor mit sem_get() erstellt wurde. |
|
| $non_blocking | bool | false | Wenn true, blockiert die Funktion nicht, sondern gibt sofort false zurück, falls der Semaphor nicht verfügbar ist. Standard ist false (blockierendes Verhalten). |
Rückgabewert
true zurück, wenn der Semaphor erfolgreich angefordert wurde. Gibt false zurück, wenn non_blocking auf true gesetzt ist und der Semaphor gerade belegt ist, oder wenn ein Fehler aufgetreten ist.Beispiele
Kritische Sektion mit Semaphor schützen
<?php
// Semaphor erstellen (Schlüssel, max. gleichzeitige Prozesse, Berechtigungen)
$semaphore = sem_get(ftok(__FILE__, 'a'), 1, 0666, true);
if ($semaphore === false) {
die('Semaphor konnte nicht erstellt werden.');
}
// Semaphor anfordern (blockiert, bis er verfügbar ist)
if (sem_acquire($semaphore)) {
echo 'Kritische Sektion betreten.' . PHP_EOL;
// Hier: exklusiver Zugriff auf gemeinsame Ressource
sleep(1); // Simulierte Arbeit
echo 'Kritische Sektion verlassen.' . PHP_EOL;
// Semaphor freigeben
sem_release($semaphore);
} else {
echo 'Semaphor konnte nicht angefordert werden.' . PHP_EOL;
}
?>
Nicht-blockierender Semaphor-Zugriff
<?php
$semaphore = sem_get(ftok(__FILE__, 'b'), 1, 0666, true);
if ($semaphore === false) {
die('Semaphor konnte nicht erstellt werden.');
}
// Nicht-blockierend versuchen
if (sem_acquire($semaphore, true)) {
echo 'Semaphor erhalten, führe Aufgabe aus.' . PHP_EOL;
// Exklusive Arbeit
sleep(1);
sem_release($semaphore);
} else {
echo 'Semaphor ist belegt, überspringe Aufgabe.' . PHP_EOL;
// Alternative Behandlung, z. B. Queue-Eintrag oder Logging
}
?>
// Wichtig · Fallstricke
Nur unter Unix/Linux verfügbar: System-V-Semaphoren sind ein POSIX-IPC-Mechanismus und stehen unter Windows nicht zur Verfügung. Skripte, die sem_acquire() verwenden, sind daher nicht portabel.
Deadlock-Gefahr: Wenn ein Prozess den Semaphor acquirt, aber nie sem_release() aufruft (z. B. durch einen unbehandelten Fehler oder ein abruptes Prozessende), kann es zu Deadlocks kommen. Es empfiehlt sich daher, sem_release() in einem finally-Block oder über einen register_shutdown_function()-Handler aufzurufen.
Konfiguration: Die PHP-Extension sysvsem muss beim Kompilieren aktiviert sein (--enable-sysvsem). Seit PHP 8.0 liefert sem_get() ein SysvSemaphore-Objekt statt einer Ressource.