Comunicacion entre procesos en PHP

Escrito el 13 Febrero, 2001 – 9:02 | por storm | 4.646 lecturas

PHP dispone de varias funciones que permiten a distintos procesos PHP comunicarse entre si pero la mayoria de los programadores desconoce su uso. En este articulo analizamos como utilizar memoria compartida y semaforos desde PHP y un nuevo mundo de posibilidades se hace realidad.

Comunicacion entre procesos en PHP

Garland Foster

“Preoptimization is the root of all evil (Donald Knuth)”

Preparacion

En este articulo vamos a explicar como manejar memoria compartida y semaforos desde PHP, para ello es necesario tener el php compilado con las siguientes opciones:


--enable-shmop
--enable-sysvsem

Las dos extensiones que vamos a usar son la extension de memoria compartida y la extension de semaforos, vamos aver que hacemos con cada una de ellas luego..

¿Que es IPC?

IPC (Inter-process communication) es un mecanismo standard de Unix para comunicar procesos entre si. Procesos que residen, vale la aclaracion, todos en la misma maquina. Basicamente IPC define 3 formas distintas de comunicacion: colas de mensajes, segmentos de memoria compartida y semaforos. En este articulo vamos a discutir el uso de semaforos y memoria compartida.

Usando memoria compartida desde PHP

El uso de segmentos de memoria compartida es una muy buena forma de comunicar procesos entre si. Basicamente se define un segmento de memoria que puede ser compartido por varios procesos, si un proceso escribe en el segmento los demas procesos pueden ver estos datos. En PHP podemos controlar con esta tecnica el numero de procesos corriendo, o poner datos en la memorua evitando que otros procesos tengan que generar la misma informacion que ya fue generada por otros procesos. En aplicaciones de cache criticas el uso de memoria como medio de almacenamiento temporal es ampliamente mas eficiente que el uso de un archivo del file-system

Para crear un segmento de memoria compartida usamos:

$shm_id = shmop_open($key, $mode, $perm, $size);

Donde:

  • $key es el numero que idnetifica el segmento de memoria compartida, todos los procesos que quieran acceder a este un mismo segmento deben conocer este numero como clave para acceder al segmento.
  • $mode es el modo de creacion, “c” es usado para crear un segmento mientras que “a” se usa para acceder a un segmento ya creado
  • $perm define los permisos del segmento de acuerdo al mecanismo de permisos de Unix
  • $size define el taman˜o del segmento

La funcion devuelve un id que debermos usar para leer/escribir en el segmento. No es similar a un identificador de archivo ya que las funciones que se usan para manipular memoria compartida son otras.

Ejemplo

$shm_id = shmop_open(0xff3, "c", 0644, 100);

En el ejemplo creamos un segmento de memoria compartida de 100 bytes.

Si queremos acceder a un segmento ya existente usamos shmop_open seteando como 0 el tercer y cuarto parametros de la funcion. Si queremos crear o acceder a un segmento segun corresponda procedemos como si estuviesemos creandolo, si el segmento ya existe simplemente accedemos al mismo.

Que hicimos?

Existen algunas utilidades Unix que pueden llamarse desde la linea de comandos para monitorear y controlar recursos de IPC, por ejemplo podemos usar “ipcs” para chequear que recursos estan creados y algunos parametros de los mismos.

Ejemplo

------ Shared Memory Segments --------key       shmid     owner     perms     bytes     nattch    status0x00280267 0         root      644       1048576   30x00000000 1         nobody    600       46084     10        dest0x00000000 2         nobody    600       46084     8         dest0x00000ff3 131       nobody    644       100       0

------ Semaphore Arrays --------key       semid     owner     perms     nsems     status0x00280269 0         root      666       14

------ Message Queues --------key       msqid     owner     perms     used-bytes  messages

Como podemos ver tenemos 4 segmentos de memoria compartida creados, el ultimo con (key 0x0000ff3) es el que creamos en nuestro ejemplo. Podemos ver las propiedades de los segmentos, como el creador, permisos, tamaño y numero de procesos que estan usando el segmento en la salida del comando ipcs.

Regresando al PHP

Si queremos eliminar un segmento de memoria compartida podemos usar la siguiente instruccion desde PHP:

shmop_delete($id);

El $id que usamos es el que devolvio oportunamente la funcion shmop_open al crear o acceder al segmento.

Si queremos remover el segmento desde la linea de comando podemos usar el comando ‘ipcrm shmid’ por ejemplo ‘ipcrm 131’ (en nuestro ejemplo) eliminaria el segmento que creamos desde PHP.

ATENCION: Si usamos ipcrm como “root” debemos tener mucho cuidado revisando que segmento que el segmento que vamos a borrar sea realmente el que queremos eliminar. Si eliminamos otros segmentos pertenecientes a otros procesos podemos producir resultados inesperados y que en general son bastante malos…

Leyendo y escribiendo datos

Para escribir datos en un segmento de memoria compartida usamos:

int shmop_write (int shmid, string data, int offset)

shmid es el id que devolvio shmop_open, data son los datos (que mas?) y el offset es el desplazamiento dentro del segmento (0 para comenzar a escribir al comienzo del mismo)

Para leer usamos:

string shmop_read (int shmid, int start, int count)

Indicamos la posicion (offset) desde la cual queremos leer (0 para el comienzo del segmento) y el numero de bytes a leer. Usando memoria compartida los datos no tienen ningun significado mas alla de ser tiras de bytes, en la mayoria de las implementaciones es bueno construir clases que manejen memoria compartida encargandose de proveer interfases para guaradar strings, objetos u otros tipos de datos. La clase se encarga entonces de manipular las longitudes y de abstraer el concepto de tira de bytes en memoria del programador.

Dos procesos

No tendremos problema alguno creando, accediendo, leyendo y escribiendo un segmento de memoria compartida desde un unico proceso aislado. Pero podemos encontrar algunos problemas cuando mas de un proceso al mismo tiempo trata de usar el segmento, estamos a punto de ingresar al facinante mundo de la concurrencia de procesos y el problema de la exclusion mutua.

Supongamos que tenemos dos procesos leyendo y escribiendo datos de un mismo segmento de memoria compartida. Si dos procesos tratan de escribir datos en la misma posicion de la memoria al mismo tiempo podemos obtener incosistencias, esto se conoce como el “problema de exclusion mutua” existe mucha informacion y literatura al respecto principalmente en libros sobre sistemas operativos. Una forma sencilla de lograr exclusion mutua es utilizando semaforos, y es el mecanismo que vamos a estudiar a continuacion.

Semaforos

Los semaforos son otro de los recursos de IPC, podemos ver informacion sobre los semaforos del sistema con ipcs y removerlos con ipcrm. Para crear un semaforo desde Php se usa:

int sem_get (int key [, int max_acquire [, int perm]])

El semaforo es creado si es necesario o accedido si ya existia. La funcion devuelve un identificador que es usado para manipular el semaforo. max_acquiere indica el maximo numero de procesos que pueden adquirir el semaforo sin liberarlo, el default es 1. Los permisos se setean como de constumbre.

Una vez que tenemos el semaforo podemos hacer dos cosas con el: adquirirlo y liberarlo. Cuando adquirimos un semaforo podemos pensar que lo estamos incrementando y si tratamos de incrementarlo mas alla de la cantidad seteada con max_acquire el proceso se bloqueara hasta que otro proceso libere el semaforo y habilite al proceso bloqueado a adquirirlo. En semaforos binarios, los mas comunes en el 90\% de los casos solamente un proceso puede adquirir el semaforo, otros procesos que quieran adquirir el semaforo se quedaran bloqueados hasta que el proceso que tiene el semaforo lo libere.

Para adquirir y liberar semaforos usamos:

int sem_acquire (int sem_identifier)
int sem_release (int sem_identifier)

Donde el identificador es el que obtuvimos con sem_get

Un protocolo simple de exclusion mutua.

Podemos usar el siguiente protocolo para lograr exclusion mutua desde PHP:

$semid=sem_get(0xee3,1,0666);$shm_id = shmop_open(0xff3, "c", 0644, 100);sem_acquire($semid);/* If we are here we are alone! */WRITE TO THE SHARED SEGMENT HEREsem_release($semid);

Como podemos ver el mecanismo es simple, se adquiere el semaforo, se hace algo y luego se libera el semaforo. Podemos estar seguros de que es imposible que dos procesos este escribiendo al mismo tiempo porque una vez que uno adquiere el semaforo los demas se bloquean hasta que el semaforo sea liberado. Las lineas entre sem_acquire y sem_release se conocen como “seccion critica” es decir las zonas donde no queremos que dos procesos concurran al mismo tiempo.

Un comentario interesante es que en la implementacion de semaforos de PHP el proceso que libera el semaforo debe ser el mismo que lo adquirio. Un proceso no puede liberar un semaforo adquirido por otro proceso. Esto no es habitual en otros lenguajes que usan IPC por lo que debemos tenerlo en cuenta.

Es importante destacar que solamente tenemos que preocuparnos por la exclusion mutua entre escritores, que mas de un proceso lea el mismo segmento de memoria compartida a la vez no presenta problema alguno pero si hay un proceso “escritor” entonces el proceso debe ser el unico que accede a la memoria. Este es un conocido problema de concurrencia conocido como el problema de los lectores-escritores.

Aplicaciones

Existen varias aplicaciones para IPC, desde algunos recursoso simples de optimizacion como guardar en memoria compartida archivos de configuracion parseados hasta avanzados motores de busqueda, sistemas de autenticacion o cache.

Garland Foster

You must be logged in to post a comment.

Buscar: