InfinityQuest - Programming Code Tutorials and Examples with Python, C++, Java, PHP, C#, JavaScript, Swift and more

Menu
  • Home
  • Sitemap

Python Programming Language Best Tutorials and Code Examples

Learn Python Right Now!
Home
PHP
Sharing Variables Between Processes in PHP
PHP

Sharing Variables Between Processes in PHP

InfinityCoder November 21, 2016

You want a way to share information between processes that provides fast access to the shared data.

Use the data store functionality of the APC extension, as shown in Example 5-4.

Example 5-4. Using APC’s data store

1
2
3
4
5
6
// retrieve the old value
$population = apc_fetch('population');
// manipulate the data
$population += ($births + $immigrants - $deaths - $emigrants);
// write the new value back
apc_store('population', $population);

If you don’t have APC available, use one of the two bundled shared memory extensions, shmop or System V shared memory.
With shmop, you create a block and read and write to and from it, as shown in Example 5-5.

Example 5-5. Using the shmop shared memory functions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// create key
$shmop_key = ftok(__FILE__, 'p');
// create 16384 byte shared memory block
$shmop_id = shmop_open($shmop_key, "c", 0600, 16384);
// retrieve the entire shared memory segment
$population = shmop_read($shmop_id, 0, 0);
// manipulate the data
$population += ($births + $immigrants - $deaths - $emigrants);
// store the value back in the shared memory segment
$shmop_bytes_written = shmop_write($shmop_id, $population, 0);
// check that it fit
if ($shmop_bytes_written != strlen($population)) {
   echo "Can't write all of: $population\n";
}
// close the handle
shmop_close($shmop_id);

With System V shared memory, you store the data in a shared memory segment, and guarantee exclusive access to the shared memory with a semaphore, as shown in Example 5-6.
Example 5-6. Using the System V shared memory functions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$semaphore_id = 100;
$segment_id = 200;
// get a handle to the semaphore associated with the shared memory
// segment we want
$sem = sem_get($semaphore_id,1,0600);
// ensure exclusive access to the semaphore
sem_acquire($sem) or die("Can't acquire semaphore");
// get a handle to our shared memory segment
$shm = shm_attach($segment_id,16384,0600);
// Each value stored in the segment is identified by an integer
// ID
$var_id = 3476;
// retrieve a value from the shared memory segment
if (shm_has_var($shm, $var_id)) {
   $population = shm_get_var($shm,$var_id);
}
// Or initialize it if it hasn't been set yet
else {
   $population = 0;
}
// manipulate the value
$population += ($births + $immigrants - $deaths - $emigrants);
// store the value back in the shared memory segment
shm_put_var($shm,$var_id,$population);
// release the handle to the shared memory segment
shm_detach($shm);
// release the semaphore so other processes can acquire it
sem_release($sem);

If you have the APC extension available, its data store is an extremely convenient way to share information between separate PHP processes across different requests.

The apc_store() function takes a key and a value and stores the value associated with the specified key.

You can also supply an optional time to live (TTL) as a third argument to apc_store() to limit the number of seconds the value is stored in the cache.

Once you’ve stored something, retrieve it by passing apc_fetch() the key.

Because apc_fetch() returns the value stored, or false on failure, it can be difficult to distinguish between a successful call that returned a false value and a failed call.

To help with this apc_fetch() supports a second by-reference argument which is set to true or false indicating whether the call succeeded, as follows:

1
2
3
4
5
6
// Shucks, you failed the test!
apc_store('passed the test?', false);
 
// $results is false, because the stored value was false
// $success is true, because the call to apc_fetch() succeeded
$results = apc_fetch('passed the test?', $success);

In addition to store and fetch, APC also functions for more complicated data manipulation.
The apc_inc() and apc_dec() functions atomically increment and decrement a stored number.

This makes them very useful for speedy counters.

You can also implement some lightweight locking by using the apc_add() function, which only inserts a variable into the data store if nothing already exists at that key. Example 5-7 shows how to do that.
Example 5-7. Using apc_add( ) to implement locking

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function update_recent_users($current_user) {
   $recent_users = apc_fetch('recent-users', $success);
   if ($success) {
      if (! in_array($current_user, $recent_users)) {
          array_unshift($recent_users, $current_user);
      }
   }
   else {
      $recent_users = array($current_user);
   }
   $recent_users = array_slice($recent_users, 0, 10);
   apc_store('recent-users', $recent_users);
}
 
$tries = 3;
$done = false;
 
while ((! $done) && ($tries-- > 0)) {
    if (apc_add('my-lock', true, 5)) {
        update_recent_users($current_user);
        apc_delete('my-lock');
        $done = true;
    }
}

In Example 5-7, the call to apc_add(‘my-lock’, true, 5) means “Insert a true value at key my-lock only if it’s not already there, and expire it automatically after five seconds.”
So if this succeeds, any subsequent request that attempts the same thing (in the next five seconds) will fail until the apc_delete(‘my-lock’) call in the first request removes the entry from the data store.

The update_recent_users() call inside the loop, as an example, maintains an array of the 10 most recent users. The loop will try three times to obtain the lock and then quit.
If you don’t have APC available, you can use a shared memory extension to accomplish similar in-memory data sharing, albeit with a little more work.
A shared memory segment is a slice of your machine’s RAM that different processes (such as the multiple web server processes that handle requests) can access.

The shmop and System V shared memory extensions solve the similar problem of allowing you to save information between requests in a fast and efficient manner, but they take slightly different approaches and have slightly different interfaces as a result.
The shmop functions have an interface similar to the familiar file manipulation. You can open a segment, read in data, write to it, and close it.

Like a file, there’s no built-in segmentation of the data, it’s all just a series of consecutive characters.
In Example 5-5, you first create the shared memory block.

Unlike a file, you must predeclare the maximum size.

In this example, it’s 16,384 bytes:

1
2
3
4
// create key
$shmop_key = ftok(__FILE__, 'p');
// create 16384 byte shared memory block
$shmop_id = shmop_open($shmop_key, "c", 0600, 16384);

Just as you distinguish files by using filenames, shmop segments are differentiated by keys. Unlike filenames, these keys aren’t strings but integers, so they’re not easy to remember.
Therefore, it’s best to use the ftok() function to convert a human-friendly name, in this case the filename in the form of __FILE__, to a format suitable for shmop_open().

The ftok() function also takes a one-character project identifier. This helps you avoid collisions in case you accidently reuse the same string. Here it’s p, for PHP.

Once you have a key, pass it to shmop_create(), along with the flag you want, the file permissions (in octal), and the block size. See Table 5-2 for a list of suitable flags.

These permissions work just like file permissions, so 0600 means that the user that created the block can read it and write to it.

In this context, user doesn’t just mean the process that created the semaphore, but any process with the same user ID.

Permissions of 0600 should be appropriate for most uses, in which web server processes run as the
same user.

Table 5-2. shmop_open() flags

Flag Description
a

c

w

n

Opens for read-only access.

Creates a new segment. If it already exists, opens it for read and write access.

Opens for read and write access.

Creates a new segment, but fails if one already exists. Useful to avoid race conditions

Once you have a handle, you can read from the segment using shmop_read() and manipulate the data:

1
2
3
4
// retrieve the entire shared memory segment
$population = shmop_read($shmop_id, 0, 0);
// manipulate the data
$population += ($births + $immigrants - $deaths - $emigrants);

This code reads in the entire segment. To read in a shorter amount, adjust the second and third parameters. The second parameter is the start, and the third is the length.

As a shortcut, you can set the length to 0 to read to the end of the segment.
Once you have the adjusted data, store it back with shmop_write() and release the handle with shmop_close():

1
2
3
4
5
6
7
8
// store the value back in the shared memory segment
$shmop_bytes_written = shmop_write($shmop_id, $population, 0);
// check that it fit
if ($shmop_bytes_written != strlen($population)) {
    echo "Can't write all of: $population\n";
}
// close the handle
shmop_close($shmop_id);

Because shared memory segments are of a fixed length, if you’re not careful, you can try to write more data than you have room.

Check to see if this happened by comparing the value returned from shmop_write() with the string length of your data.

They should be the same. If shmop_write() returned a smaller value, then it was only able to fit that many bytes in the segment before running out of space.
In constrast to shmop, the System V shared memory functions behave similarly to an array. You access slices of the segment by specifying a key, such as population, and manipulate them directly.

Depending on what you’re storing, this direct access can be more convenient. However, the interface is more complex as a result, and System V shared memory also requires you to do manage locking in the form of semaphore.

A semaphore makes sure that the different processes don’t step on each other’s toes when they access the shared memory segment.

Before a process can use the segment, it needs to get control of the semaphore. When it’s done with the segment, it releases the semaphore for another process to grab.
To get control of a semaphore, use sem_get() to find the semaphore’s ID. The first argument to sem_get() is an integer semaphore key.

You can make the key any integer you want, as long as all programs that need to access this particular semaphore use the same key.

If a semaphore with the specified key doesn’t already exist, it’s created; the maximum number of processes that can access the semaphore is set to the second argument of sem_get() (in this case, 1); and the semaphore’s permissions are set to sem_get()’s third argument (0600). Permissions here behave like they do with files and shmop.

For example:

1
2
3
4
5
6
7
$semaphore_id = 100;
$segment_id = 200;
// get a handle to the semaphore associated with the shared memory
// segment we want
$sem = sem_get($semaphore_id,1,0600);
// ensure exclusive access to the semaphore
sem_acquire($sem) or die("Can't acquire semaphore");

sem_get() returns an identifier that points to the underlying system semaphore. Use this ID to gain control of the semaphore with sem_acquire().

This function waits until the semaphore can be acquired (perhaps waiting until other processes release the
semaphore) and then returns true.

It returns false on error. Errors include invalid permissions or not enough memory to create the semaphore. Once the semaphore is acquired, you can read from the shared memory segment:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// get a handle to our shared memory segment
$shm = shm_attach($segment_id,16384,0600);
// each value stored in the segment is identified by an integer
// ID
$var_id = 3476;
// retrieve a value from the shared memory segment
if (shm_has_var($shm, $var_id)) {
   $population = shm_get_var($shm,$var_id);
}
// or initialize it if it hasn't been set yet
else {
   $population = 0;
}
// manipulate the value
$population += ($births + $immigrants - $deaths - $emigrants);

First, establish a link to the particular shared memory segment with shm_attach(). As with sem_get(), the first argument to shm_attach() is an integer key.

This time, however, it identifies the desired segment, not the semaphore. If the segment with the specified key doesn’t exist, the other arguments create it.

The second argument (16384) is thesize in bytes of the segment, and the last argument (0600) is the permissions on the segment.

 shm_attach(200,16384,0600) creates a 16K shared memory segment that can be read from and written to only by the user who created it.

The function returns the identifier you need to read from and write to the shared memory segment.

After attaching to the segment, pull variables out of it with shm_get_var($shm, $var_id).

This looks in the shared memory segment identified by $shm and retrieves the value of the variable with integer key $var_id. You can store any type of variable in shared memory.

Once the variable is retrieved, it can be operated on like other variables.
shm_put_var($shm, $var_id ,$population) puts the value of $population back intothe shared memory segment at variable $var_id.
You’re now done with the shared memory statement. Detach from it with shm_detach() and release the semaphore with sem_release() so another process can use it:

1
2
3
4
// release the handle to the shared memory segment
shm_detach($shm);
// release the semaphore so other processes can acquire it
sem_release($sem);

Shared memory’s chief advantage is that it’s fast. But because it’s stored in RAM, it can’t hold too much data, and it doesn’t persist when a machine is rebooted (unless you take special steps to write the information in shared memory to disk before shutdown and then load it into memory again at startup).
You cannot use System V shared memory under Windows, but the shmop functions work fine.

Share
Tweet
Email
Prev Article
Next Article

Related Articles

Storing Passwords in PHP
You need to keep track of users’ passwords, so they …

Storing Passwords in PHP

Parsing Complex XML Documents in PHP
You have a complex XML document, such as one where …

Parsing Complex XML Documents in PHP

About The Author

InfinityCoder
InfinityCoder

Leave a Reply

Cancel reply

Recent Tutorials InfinityQuest

  • Adding New Features to bash Using Loadable Built-ins in bash
    Adding New Features to bash Using Loadable …
    June 27, 2017 0
  • Getting to the Bottom of Things in bash
    Getting to the Bottom of Things in …
    June 27, 2017 0

Recent Comments

  • fer on Turning a Dictionary into XML in Python
  • mahesh on Turning a Dictionary into XML in Python

Categories

  • Bash
  • PHP
  • Python
  • Uncategorized

InfinityQuest - Programming Code Tutorials and Examples with Python, C++, Java, PHP, C#, JavaScript, Swift and more

About Us

Start learning your desired programming language with InfinityQuest.com.

On our website you can access any tutorial that you want with video and code examples.

We are very happy and honored that InfinityQuest.com has been listed as a recommended learning website for students.

Popular Tags

binary data python CIDR convert string into datetime python create xml from dict python dictionary into xml python how to create xml with dict in Python how to write binary data in Python IP Address read binary data python tutorial string as date object python string to datetime python

Archives

  • June 2017
  • April 2017
  • February 2017
  • January 2017
  • December 2016
  • November 2016
Copyright © 2021 InfinityQuest - Programming Code Tutorials and Examples with Python, C++, Java, PHP, C#, JavaScript, Swift and more
Programming Tutorials | Sitemap