Using Shared Memory from PHP
by Alexander Prohorenko05/13/2004
IPC is one of the most important features of the UNIX systems. It allows two processes to communicate with each other. In this article we'll work with two System V IPC functions, semaphores and shared memory. System V IPC originated in SVR2, but has implementations by numerous vendors. It's also available in SVR4.
IPC is a complex concept. The term includes various mechanisms of data exchange between processes started on one system. IPC lets you avoid creating a huge application with a big set of the diversified functions in favor of using separate, small applications that can exchange data with each other. While this is more of a traditional Unix approach, using separate applications allows multiprocessor systems to execute applications in separate threads to reduce the time of performing specific tasks.
At a very high-level, we can divide interprocess communication into the most important and big parts:
- Messaging (pipes and message queues)
- Shared memory
- RPC (remote procedure calls)
- Synchronization (semaphores and any kind of locks)
- Network communication (sockets API)
This article introduces shared memory and synchronization (semaphores). A detailed explanation of these parts will take too much time — there's a huge amount of different material and documentation. If you're interested in further detail, there are multiple books dedicated to IPC.
IPC Identifiers
Each IPC object (whether a message queue, a semaphore, or a shared memory segment) has a unique IPC identifier. This identifier allows the kernel to determine the identify of an IPC object. For example, to refer to a specific shared memory segment, you only need to know the unique ID attached to the segment.
Beware that the IPC identifier is unique for its object's type only. That
is, say, only one message queue can have the 12345 identifier,
though the number 12345 can have any multitude of semaphores and/or a shared
memory segment.
IPC Keys
How do you find an IPC identifier? You need a key. The first step to building an environment between applications is coordinating the use of keys. Think of it this way: to call someone, you have to know his phone number. The telephone company has to know how to pass your call to the recipient. Only when he responds can the connection take place.
In the case of System V IPC, the telephone connects IPC objects of the same type; the Telephone Company or routing method is the IPC key.
Applications need to generate their own keys. The ftok()
function will do this for both the client and the server. The key returned
from ftok() relies on the inode value and the lowest minor number
of the first argument file and from the second argument literally. This does
not guarantee originality, but the application can check for collisions and
generate new keys as necessary.
key_t mykey;
mykey = ftok ("/tmp/myapp", 'a');
In the fragment above, the /tmp/myapp directory mixes with the
literal identifier a to generate the key. Another widespread
example is to use the current directory:
key_t mykey;
mykey = ftok(".", 'a');
The key generation algorithm relies on the discretion of the application
programmer. Any method should take into account race conditions and deadlock-prevention measures. To achieve our demonstrational goals, we will limit
ourselves to ftok(). If we agree that each client process should
run from its own unique home directory, all generated keys will always be
satisfactory.
The following IPC system calls the value of the returned key to create or improve the access to IPC objects.
The ipcs command shows the status of all System V IPC
objects.
ipcs -q: show messages queue only
ipcs -s: show semaphore only
ipcs -m: show shared memory only
ipcs --help: for inquisitive ones
All three object categories show by default. Let's look at the following
unpretentious ipcs derivation:
------ Shared Memory Segments --------
shmid owner perms bytes nattch status
------ Semaphore Arrays --------
^semid owner perms nsems status
------ Message Queues --------
msqid owner perms used-bytes messages
0 root 660 5 1
Here we can see the solitary message queue with the identifier
0. It belongs to the root user and has the access rights
660, or -rw-rw---. The queue holds one 5-byte message.
The ipcs command is a very powerful mechanism for spying on the
kernel memory of IPC objects.
The ipcrm Command
ipcrm deletes IPC objects from the kernel. However, as IPC
objects can be deleted through system calls in the user's program, there is
often no need to delete them by hand. The command is very simple:
ipcrm -type id
It's necessary to note the type of object to delete with a special switch.
See the manpage for more details. You can find an IPC id with the
ipcs command. Remember, the ID is unique only within the object's
type. That's why we have to name the type when deleting the object.
Semaphores
The best way to imagine semaphores is as counters that manage access to public resources. Usually they are used as locks, disallowing one process to access something already in use by another process. Semaphores can also provide exclusive access to the resources of the current machine or to limit the number of processors using the resource simultaneously.
This module also provides the functions to work with System V shared
memory. Shared memory provides access to global variables between processes.
httpd daemons and even other programs (in Perl, C, and other
languages) can access this data to achieve global data exchange. Remember, though, that shared memory is not protected from simultaneous access.
Table 1 show Unix variables that tune shared-memory limitations. Each Unix variant has specific documentation on these variables. For example, on FreeBSD, they're part of the kernel configuration. You'll need to recompile your kernel if you make changes.
Table 1. Unix Shared Memory Variables
SHMMAX |
The maximum amount of shared memory, normally 131072 bytes |
SHMMIN |
The minimum amount of shared memory, normally 1 byte |
SHMMNI |
The maximum number of shared memory segments in the system, normally 100 |
SHMSEG |
The maximum number of shared memory segments per process, normally 6 |
The messages functions can send and receive messages to and from other processes. They are a simple and effective means of data exchange without having to use Unix domain sockets.
Pages: 1, 2 |