Skip to content

Instantly share code, notes, and snippets.

@mspreij
Created October 31, 2023 12:00
Show Gist options
  • Save mspreij/4c571ab93123520262ac3b8c5c0e0241 to your computer and use it in GitHub Desktop.
Save mspreij/4c571ab93123520262ac3b8c5c0e0241 to your computer and use it in GitHub Desktop.
Example script that uses pcntl_fork() to fork itself a few dozen times, and System V IPC functions to create a message queue,
let the child processes send data to it and the parent process read and display it.
#!/usr/bin/env php
<?php
// Create or attach to a message queue
$queue = msg_get_queue(ftok(__FILE__, 'a'), 0600); # set permissions so that only the owner can read/write to this queue
# ftok() creates a message queue key based on the file's inode and a single character project identifier. The latter lets
# one create several queues all based on/in the same file.
$child_count = 3;
$records = query($sql....);
// Fork child processes
for ($i = 0; $i < $child_count; $i++) {
# pcntl_fork() splits the script at the point where it is called. The two copies of the script know what they are
# based on the value of $pid: 0 for the child, positive int for the parent (it will be the child's PID) or -1 for failure.
$pid = pcntl_fork();
if ($pid == -1) {
die('Could not fork');
} elseif ($pid) {
# Parent process
// Do nothing, will wait for child messages later
} else {
# Child process: do all the Child things, send the results to the queue, then exit
$process_records = array_slice($records, $i*10, 10);
# process $process_records here..
# Send a message to the parent
msg_send($queue, 1, "Child $i done with job, result: ...");
exit(0);
}
}
# Parent process waits to receive messages from all child processes
for ($i = 0; $i < $child_count; $i++) {
msg_receive($queue, 0, $msgType, 1024, $message, true);
echo "Received message: $message\n";
}
# Destroy the message queue, otherwise it hangs around in memory. ipcs will show you current message queues.
msg_remove_queue($queue);
# You might be tempted to use register_shutdown_function() for this but that will also fire as soon as the first child
# process exits, sooo.. don't.
# If all else fails, from the cli use ipcrm -q <msqid>, where the msqid shows up under the output of ipcs.
# Other considerations:
# - make sure the child process Always exits, and always sends something to the queue before doing so, wrapping it in a try/catch
# should work
# - counting $children++ inside the child process does not work, this variable will not be incremented in the parent process.
# you can increment it in the parent branch of the $pid fork.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment