Found at: http://publish.ez.no/article/articleprint/46

Inter-Process Communication in PHP



Luis returns with an article covering the real computer science stuff, how to use shared memory and semaphores.

Inter-Process Communication in PHP

Luis Argerich (Salutia.com)

Luis returns with an article covering the real computer science stuff, how to use shared memory and semaphores.

"Preoptimization is the root of all evil (Donald Knuth)"

Preparation


In this article I'm going to discuss the use of IPC (Inter-Process-Communication) mechanisms from PHP4, you'll need PHP 4.0.4 or better compiled with the following strings:

--enable-shmop --enable-sysvsem 


The two extensions that we are going to use are the Shared Memory extension and the Semaphores extension, we are going to see what to do with each one later.

What is IPC


IPC (Inter-process communication) is a standard Unix mechanism to communicate processes in the same machine, basically IPC defines 3 different ways of communication: message queues, shared memory and semaphores. We are going to discuss shared memory and semaphores in this article.

Using Shared Memory Segments from PHP


The use of shared memory segments is a very good way to communicate between processes, basically you define a memory segment that can be shared between processes, if a process writes to the memory with some data the other processes can see it. In PHP you can for example control, for example the number of processes running, or put some data in memory to prevent all the php scripts from doing the same thing, generating the same result.

To create a shared memory segment you use:


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


Where:

  • $key is a number to identify the shared memory segment, all the scripts wanting to access a given segment must know the key
  • $mode is the creation mode "c" is used to create a segment, "a" is used to access an existing segment
  • $perm defines the permissions to the segment
  • $size defines the size of the segment

    The function returns an id which you have to use to read/write the segment (don't use it as a file, there are
    special functions that we'll cover later)

    Example:


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


    In this example we created a segment of 100 bytes.

    If you want to access an existing segment you use shmop_open setting 0 as the third and fourth parameters.If you want to create or access a segment you proceed as if you were creating it.

    What have I done?


    There're some command line utilities in Unix to control IPC resources, you can use "ipcs" to check which resources are created and so

    Example

    ------ Shared Memory Segments --------
    key       shmid     owner     perms     bytes     nattch    status
    0x00280267 0         root      644       1048576   3
    0x00000000 1         nobody    600       46084     10        dest
    0x00000000 2         nobody    600       46084     8         dest
    0x00000ff3 131       nobody    644       100       0
    
    ------ Semaphore Arrays --------
    key       semid     owner     perms     nsems     status
    0x00280269 0         root      666       14
    
    ------ Message Queues --------
    key       msqid     owner     perms     used-bytes  messages
    


    As we can see we have 4 shared memory segments created, the last one (key 0x00000ff3) is the one that we created with our example. You can see some properties of IPC resources with IPCs

    Going back


    If you want to delete/remove a shared memory segment you can use the following PHP instruction:


    shmop_delete($id);


    The $id you have to use is the one that shmop_open returns when you create/access the segment

    If you want to remove the segment from the command line you can use 'ipcrm shmid' for example 'ipcrm 131' (in our example) to delete the segment

    WARNING: If you use ipcrm as root be very careful checking which segments you delete because you can destroy other processes' segments with unpredictable (almost always bad) results.

    Reading and writing data


    To write data to a shared memory segment you use:


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


    The shmid is the id returned by shmop_open, data is data and offset is the offset inside the segment (0 to start writing from the beginning of the segment.

    To read you use:


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


    You indicate the position (offset) from which you are going to read (0=start of segment) and the number of bytes. using shared memory you just use the memory as an array of bytes, you read "x" bytes, write "y" bytes, etc. You may want to program a wraper to store strings, objects or so and let the class manage the lengths using some standard format to put and retrieve things from the segment

    Two processes


    You'll have absolutely no problem accesing, creating, reading and writing a shared segment from one isolated PHP process, but you may run into trouble using more than 1 at the same time, you are going to enter the very interesting world of concurrency and the mutual exclusion problem

    Suposse you have two processes reading and writing data in a segment, if two processes try to write data at the same time you might get garbage in the segment, you need to prevent more that one process from writing to the segment at the same time, this is known as the "mutual exclusion" problem, there's a lot of literature mainly in operating system couses regarding this subject. One easy way to achieve mutual exclusion is using semaphores, so we are going to cover this here:

    Semaphores are another IPC resource, you can check them and remove them using ipcs and ipcrm too. You create a semaphore using:


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


    The semaphore is created if necessary, the function returns an identifier used to manipulate the semaphore, max_acquire indicate the maximum number of processes that can acquire the semaphore without releasing it (default=1), permissions are set as usual.

    Once you have a semaphore you can do two things with it: "acquire it" and "release it", when you acquire a semaphore you can think of it as if you were incrementing it. If you try to increment the semaphore past "max_acquire" the process will block until the call can be completed. In binary semaphores where max_acquire is 1 only one process can have the semaphore "acquired" at the same time, other processes trying to acquire the resource will block until the process with the semaphore releases it

    To acquire/release the semaphore you use:


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


    Where the identifier is the one you got with sem_get.

    A simple mutual esclusion protocol


    You can use the following protocol to achieve mutual exclusion in 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 HERE
    sem_release($semid);


    As you can see the mechanism is simple, acquire the semaphore, do something, release the semaphore, you can be sure that two processes can't be writing at the same time because once one of them acquire the semaphore the other will block until the semaphore is released. The lines between the sem_acquire and sem_release are called "the critical zone", the zone where you don't want two or more processes at the same time

    One interesting observation is that in PHP semaphores implementation the process releasing the semaphore must be the same that acquired it, this is not usual in IPC where a process may acquire a semaphore and let other process release it.

    You should note that you only have to take care of mutual exclusion between writers, more than one process reading the same segment don't imply any risk of inconsitency.

    Applications


    There're several applications for IPC, from the simple action to keep a parsed configuration file shared between processes to advanced engines and authentication systems. I've used this extensions to optimize a bottle-neck in a web site keeping a big file that all the scripts needed to read in memory, you can find some problems that might be solved using this or even create powerful applications with this in mind.


    | Back to normal page view |