Using the shared memory in PHP

Using the shared memory in PHP

IPC ("Inter-Process Communication") is one the most important features of the UNIX family operative systems. It allows different processes to interact. In that article we’ll talk about two System V IPC technologies: semaphores and shared memory.

IPC conception has several components. Term implies different mechanisms of data exchanging between processes started in the same system. IPC allows to escape creating a large application with big number of functions.

We can divide the interprocess interaction to the following issues:

  • Messages: pipes and message queues
  • Shared memory
  • RPC (remote procedure calls)
  • Synchronization: semaphores and other types of blocking
  • Network interaction

IPC ids

Every IPC object has unique id that allows operating-system kernel to identify that object. For example, for referring to the definite segment of the shared memory the only thing you have to know is the unique id.

Don’t forget that IPC object’ id is unique only for one type of the object. In other words only one message queue can have 12345 id, although 12345 number can be used by semaphores or segments of the shared memory.

IPC keys

How is IPC id created? For that purpose you need a key. The first step for creating the interaction environment between applications is key using coordination. For example, if you want to call anybody you have to know his telephone number. Telco has to know how to send your call to the subscriber.

In the case of using System V IPC “telephone” connects one type objects. In that case Telco or routing method is IPC “key”.

Applications should generate their own keys. ftok() function can be used as for server as well as for client. Key’s value returned by ftok() function depend on the inode value and the lower value of the device id for the first argument – file and second argument – symbol. It doesn’t provide the uniqueness but applications can generate new keys if it is necessary.

key_t mykey;
mykey = ftok ("/tmp/myapp", "a");

In the example above /tmp/myapp directory is combined with the literal “a” id for the key generation. Another example is current directory using.

key_t mykey;
mykey = ftok(".", "a");

The following IPC system calls use the returned key’s value for creating or changing the access to the IPC objects.

Ipcs command displays the condition of all the System V IPC objects.

ipcs -q: how only the messages’ queues

ipcs -s: show only semaphores

ipcs -m: show only the shared memory

ipcs --help: for curious

By default there are displayed three categories of the objects. Let’s view simple example of the ipcs command fetching:

------ 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

We see the only message queue with 0 id. It belongs to the root user and has the access rights 660 or -rw-rw---. Queue has one 5-bytes message.

Ipcs command is a strong mechanism for IPC objects’ memory kernel monitoring.

Ipcrm command.

Ipcrm deletes the IPC objects from the kernel. IPC objects can be deleted by means of the system calls from the application program, that’s why the necessity of the manual deleting appears too rarely. The command is very simple:

ipcrm - type (type) id (number)

We have to indicate the type of the deleted object with parameter. IPC id can be defined by means of the ipcs command. Don’t forget that IPC object’ id is unique only for one type of the object. That’s why we have to indicate the type of the object while deleting.

Semaphores

It is better to represent the semaphores as the access counter to the public recourses. Usually they are used as a locks not allowing one process to get access for something that is currently used by another process. Semaphores can either provide with the exclusive access to the recourses of the given computer or restrict the number of processors that use the recourse at the same time.

That mechanism provides the functions for working with the System V shared memory. Shared memory provides the access to the global variables for different processes

Table 1 shows the UNIX variables which define the restriction parameters of the shared memory.

Table 1. Shared memory UNIX variables.

SHMMAX Max amount of the shared memory, usually 131072 bytes
SHMMIN Min amount of the shared memory, usually 1 byte
SHMMNI Max amount of the shared memory segments in the system, usually 100
SHMSEG Min amount of the shared memory segments for one process, usually 6

Message functions can either send or receive messages. They are the most effective and simple way of data exchange between processes without using the socket UNIX system

Shared memory and semaphores using

Shared memory is the simplest IPC type, but it requires synchronization between data saving and extraction. What is the algorithm of shared memory using? Algorithm is as follows:

  • Get the access to the shared memory using semaphores
  • Record the data to shared memory segment
  • After recording inform other programs about it using semaphores.

Synchronization using the semaphores is very important, because shared memory recourse use is similar to the file resource use where temporary access blocking and deblocking allow to escape data loss.

Now we have to learn how to use the semaphore. Actually it is very simple. The main feature is that as semaphores can block and deblock recourses they can block each other.

Here we have several examples that illustrate different functions of semaphores and shared memory.


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


That function returns semaphore’s id. It will be true in the case of success, and false in the case of error. Use id for accessing the semaphore V with the help of key.

If it is necessary semaphore can have the access rights indicated in the perm parameter. Default value is 0666. max_acquire parameter controls the amount of processes that can get the access to the semaphore at the same time. Its default value is 1.

Second call of the sem_get() function for the same key returns another id but they will point to the same semaphore.


int shm_attach(int key [, int memsize [, int perm]])


That function creates or opens the shared memory segment. shm_attach() returns the identifier for using at the gaining the access to the segment with the help of the given key. Segment size equals mem_size. Default value equals sysvshm. init_mem. Optional parameter perm defines the access rights; its default value is 0666.

First call with the given key creates the segment. Second call returns another id, ignoring other two parameters. Both parameters provide the access to the same segment of the shared memory.


mixed shm_get_var(int id, int variable_key)


That function returns the variable identified by the variable_key parameter from the shared memory segment with id identifier. That variable leaves in the shared memory.


int shm_put_var(int shm_identifier, int variable_key, mixed variable)


That function adds or updates the variable’s value set by the variable_key parameter in the shared memory segment set by the shm_identifier parameter. It allows to work with different variables.


bool sem_release(int sem_identifier)


That function releases the semaphore if it is currently used by another process. Otherwise it will show the warning. It returns true in the case of success, and false in the case of error.

If you want to keep on using the released semaphore call sem_acquire() function.


int shm_remove(int shm_identifier)


That function removes shared memory segment and its data.


bool sem_remove(int sem_identifier)


That function removes the semaphore set by the sem_identifier function if it has been created with the help of sem_get. It returns true in the case of success, and false in the case of error. If there is no any semaphore with the indicated id, there will appear warning.

Example of the code that uses shared memory.

Example 1

<?php 
MEMSIZE 
512//  hared memory size 
$SEMKEY 1;   //  semaphore key 
$SHMKEY 2;   //  shared memory key 

echo "Start.\n"

// Create the semaphore 
$sem_id sem_get($SEMKEY1); 
if (
$sem_id === false

    echo 
"Error while creating the semaphore"
    exit; 

else 
    echo 
"Semaphore $sem_id.\n created "

// Acquire the semaphore 
if (! sem_acquire($sem_id)) 

    echo 
" Error while acquiring the semaphore $sem_id.\n"
    
sem_remove($sem_id); 
    exit; 

else 
    echo 
"$sem_id.\n Semaphore is acquired successfully "

// Attach the shared memory 
$shm_id shm_attach($SHMKEY$MEMSIZE); 
if (
$shm_id === false

    echo 
"Error while attaching the shared memory.\n"
    
sem_remove($sem_id); 
    exit; 

else 
    echo 
"Successful attaching of the shared memory : $shm_id.\n"

// Record the variable 1 
if (!shm_put_var($shm_id1"Variable 1")) 

    echo 
"Error while recording the variable 1 to the shared memory $shm_id.\n"

    
// Release recourses. 
    
sem_remove($sem_id); 
    
shm_remove($shm_id); 
    exit; 

else 
    echo 
"Variable 1 has been recorded to the shared memory.\n"

// Record variable 2 
if (!shm_put_var($shm_id2"Variable 2")) 

    echo 
" Error while recording the variable 2 to the shared memory $shm_id.\n"

    
// Release recourses. 
    
sem_remove($sem_id); 
    
shm_remove ($shm_id); 
    exit; 

else 
    echo 
" Variable 2 has been recorded to the shared memory.\n"

// Read variable 1 
$var1 shm_get_var($shm_id1); 
if (
$var1 === false

    echo 
"Error while reading variable 1 from the shared memory $shm_id, " 
         
"returned value=$var1.\n"

else 
    echo 
"Variable 1 is read=$var1.\n"

// Reading variable 2 
$var2 shm_get_var ($shm_id2); 
if (
$var1 === false

     echo 
" Error while reading variable 2 from the shared memory $shm_id, " 
          
"returned value=$var2.\n"

else 
    echo 
"Variable 2 is read=$var2.\n"

// Release the semaphore 
if (!sem_release($sem_id)) 
    echo 
"Error while releasing the semaphore $sem_id.\n"
else 
    echo 
"Semaphore $sem_id is released.\n"

// Dlete the shared memory segment 
if (shm_remove ($shm_id)) 
    echo 
"Shared memory has been deleted successfully.\n"
else 
    echo 
"Error while deleting the segment $shm_id.\n"

// Delete the semaphore. 
if (sem_remove($sem_id)) 
    echo 
"Semaphore has been deleted successfully.\n"
else 
    echo 
"Error while deleting the semaphore $sem_id.\n"

echo 
"The end.\n"

?>

Example 2

<?php 
// Create the shared memory block with size 100 byes and identifier that equals 0xff3 
$shm_id shmop_open(0xff3"c"0644100); 

if(!
$shm_id

    echo 
"Error while creating the shared memory segment.\n"


// Get the size of the shared memory segment 
$shm_size shmop_size($shm_id); 
echo 
"Shared memory block with size: "$shm_size " has been created.\n"

// Write the test string to the shared memory segment 
$shm_bytes_written shmop_write($shm_id"My shared memory block"0); 

if(
$shm_bytes_written != strlen("My shared memory block ")) 

    echo 
"Error while writing data\n"


// Read the string 
$my_string shmop_read($shm_id0$shm_size); 

if(!
$my_string

    echo 
"Error while reading the shared memo\n"


echo 
"Data in the shared memory equal: ".$my_string."\n"

// Delete the block and close the shared memory segment 

if(!shmop_delete($shm_id)) 

    echo 
"Error while deleting the block."


shmop_close($shm_id); 

?>
//

 

  • Top