ConcurrencyPHPverifiedVerified

Mutex / Lock Pattern in PHP

Guarantee that only one thread at a time can access a shared resource by requiring threads to acquire an exclusive lock before proceeding.

How to Implement the Mutex / Lock Pattern in PHP

1Step 1: Define a simple mutex using file locking

class Mutex
{
    private mixed $lockFile = null;
    private bool $locked = false;

    public function __construct(
        private readonly string $name,
    ) {}

2Step 2: Acquire the lock

    public function lock(): void
    {
        $path = sys_get_temp_dir() . "/{$this->name}.lock";
        $this->lockFile = fopen($path, 'w');

        if ($this->lockFile === false) {
            throw new \RuntimeException("Cannot create lock file");
        }

        if (!flock($this->lockFile, LOCK_EX)) {
            throw new \RuntimeException("Cannot acquire lock: {$this->name}");
        }

        $this->locked = true;
    }

3Step 3: Release the lock

    public function unlock(): void
    {
        if ($this->lockFile !== null && $this->locked) {
            flock($this->lockFile, LOCK_UN);
            fclose($this->lockFile);
            $this->locked = false;
        }
    }

4Step 4: Execute a callback while holding the lock

    public function synchronized(callable $callback): mixed
    {
        $this->lock();
        try {
            return $callback();
        } finally {
            $this->unlock();
        }
    }
}

// Usage
$mutex = new Mutex('counter');
$counter = 0;

$mutex->synchronized(function () use (&$counter): void {
    $counter++;
    echo "Counter: {$counter}\n";
});

Mutex / Lock Pattern Architecture

hourglass_empty

Rendering diagram...

lightbulb

Mutex / Lock Pattern in the Real World

A single-occupancy public restroom with a door latch is a perfect mutex. The latch (lock) ensures only one person (thread) occupies the restroom (critical section) at a time. Anyone who finds the door locked must wait outside; when the occupant leaves and unlatches the door, one waiting person may enter.