Concurrencia, bloqueo de código y semáforos en php

En ciertas ocasiones necesitamos que una parte de nuestro código se ejecute por solo un usuario a la vez.
Estos bloqueos de código los utilizamos para evitar problemas de concurrencia.
En php es posible implementar estos bloqueos mediante semáforos. (Ver semáforos en el manual de php)

El problema es que no siempre nuestro hosting viene con una versión estilo System V (–enable-sysvsem) compilada de php.

Si esto es así, podemos resolver el problema ejecutando el siguiente código:

if ( !function_exists('sem_get') ) {
    function sem_get($key) { return fopen(__FILE__.'.sem.'.$key, 'w+'); }
    function sem_acquire($sem_id) { return flock($sem_id, LOCK_EX); }
    function sem_release($sem_id) { return flock($sem_id, LOCK_UN); }
}

Con esto, ahora ya podemos usar las funciones de php para semáforos (sem_get(), sem_acquire(), sem_release())

Aquí os dejamos un ejemplo práctico de cómo usar los semáforos para obtener el siguiente número de pedido disponible y actualizar el pedido actual:

$sem_key = 12;
$sem_id = sem_get($sem_key, 1);
if (! sem_acquire($sem_id)) die ('Error esperando al semaforo.');


$ref = $model->getNextPedidoReference();
$pedido->referencia = $ref;
if (!$model->Update($pedido)){
    handle_error("Error guardando el pedido");
    return;
}


if (! sem_release($sem_id)) die ('Error liberando el semaforo');

De esta forma ya podemos estar seguros de que no se podrá dar el caso de que dos usuarios obtengan el siguiente número de pedido disponible a la vez y acabes teniendo dos pedidos con la misma referencia.

Happy coding!