How to properly use PHP5 semaphores?

Short answer

  1. You don't need to create and remove semaphores within the fetch_cache function. Put sem_get() into an initialization method (such as __construct).
  2. You should remove semaphores with sem_remove(), but in a cleanup method (such as __destruct). Or, you might want to keep them even longer - depends on the logic of your application.
  3. Use sem_acquire() to acquire locks, and sem_release() to release them.

Description

sem_get()

Creates a set of three semaphores.

The underlying C function semget is not atomic. There is a possibility of race condition when two processes trying to call semget. Therefore, semget should be called in some initialization process. The PHP extension overcomes this issue by means of three semaphores:

Semaphore 0 a.k.a. SYSVSEM_SEM

Is initialized to sem_get's $max_acquire and decremented as processes acquires it.

The first process that called sem_get fetches the value of SYSVSEM_USAGEsemaphore (see below). For the first process, it equals to 1, because the extension sets it to 1 with atomic semop function right after semget. And if this is really the first process, the extension assigns SYSVSEM_SEM semaphore value to $max_acquire.

Semaphore 1 a.k.a. SYSVSEM_USAGE

The number of processes using the semaphore.

Semaphore 2 a.k.a. SYSVSEM_SETVAL

Plays a role of a lock for internal SETVAL and GETVAL operations (see man 2 semctl). For example, it is set to 1 while the extension sets SYSVSEM_SEM to $max_acquire, then is reset back to zero.

Finally, sem_get wraps a structure (containing the semaphore set ID, key and other information) into a PHP resource and returns it.

So you should call it in some initialization process, when you're only preparing to work with semaphores.

sem_acquire()

This is where the $max_acquire goes into play.

SYSVSEM_SEM's value (let's call it semval) is initially equal to $max_acquire. semop() blocks until semval becomes greater than or equal to 1. Then 1 is substracted from semval.

If $max_acquire = 1, then semval becomes zero after the first call, and the next calls to sem_acquire() fill block until semval is restored by sem_release() call.

Call it when you need to acquire the next "lock" from the available set ($max_acquire).

sem_release()

Does pretty much the same as sem_acquire(), except it increments SYSVSEM_SEM's value.

Call it when you need to no longer need the "lock" acquired previously with sem_acquire().

sem_remove()

Immediately removes the semaphore set, awakening allprocesses blocked in semop on the set (from IPC_RMID section, SEMCTL(2) man page).

So this is effectively the same as removing a semaphore with ipcrm command.

Tags:

Php

Semaphore