Working with pcntl_fork – part 1

I’ve been working with pcntl_fork and friends recently for a personal project. I worked with pcntl_* functions from a very early in my programming career and I love the challenges it presents for the traditional web programmer. Here is one of those problems.Let’s say you want to create a classic daemon which has a manager and some children. Your pseudo code might look something like:

  • Start
  • Fork forground process to create a background process, kill foreground, return control to CLI
  • Have background “master process” fork 5 children
  • Have the 5 children monitored by the master process
  • Have the master pass any signals to the children
  • Wait for the children to finish up
  • Shut down the master

In what I’m suddenly going to break into a series of posts (because I’m lazy) I’ll tackle the first two hurdles: fork the process, create a background process, create 5 children.

First one’s easy

Let’s rip some code right from one of my projects. It simply forks the foreground process and kills off the parent. Effectively “back-grounding” your process for you.

You call that function, and all of a sudden your cli app is running in the background – easy. However, as soon as you try and do more sophisticated things, you need to get a better understanding of pcntl_fork.

Revisit the definition of pcntl_fork

It’s important to remember what pcntl_fork() does. Upon execution, the current process is “copied”, for want of a better word. By the time pcntl_fork() returns control back to the calling code, there are now two processes at an identical point in the code. So, if you were thinking about creating your 5 children in a simple for loop, you need to be careful:

The code above will not create five children. The number of children it creates increases exponentially. or some crazy clever shit like that (answers on a post card , mathematicians).

More children working than crunch week at an off-shored clothes factory

With the code above, the first call to pcntl_fork() happens when $i = 0 and will create a child, then you’ll have two processes. Remember, pcntl_fork() just creates a copy of the current process, so you now have two processes both coming back to the pcntl_fork() call again for, as far as each process is concerned, where $i = 1. So, pcntl_fork() gets called again by each process, and suddenly you’ve got 4 processes. Then, when $i = 2, you’ve got 4 calls to pcntl_fork() and bam, you have another 4 processes – 8 processes in total. It’s only $i = 3 and we’ve overshot. The code to mitigate this problem this is a little less elegant:

The key is for children to break out of the for loop ASAP. By using an approach like the one above, you should be able to prevent creating unintentional fork-bombs.

You are not you, you are me

Remember that scene in (the original version of) Total Recall? No, not that one. The one where Quaid has a hologram watch and Richter’s guys aren’t really sure if they’re dealing with the copy, or the original Quaid. Well, using pcntl_fork is a lot like that, only with more bloodshed.

After a call to pcntl_fork we need to know which “version” of the application is running. You remember how fork_to_bg() returned the process id of the new child? Well, on that occasion you’re kinda guaranteed that there’s only one exit path from fork_to_bg() because after pcntl_fork, one of the processes is immediately exited. However, after we’ve called pcntl_fork 5 times from the “parent” process, we don’t know if we’re in “manager” or “children worker” land. Because forking creates a copy of the proecss, we have to code for both scenarios; manager and worker.

You can dress it up with all the OO you like, but under the hood it’s pretty low tech. Next in the series – monitoring your children.

Posted in PHP, System

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">