CentOS 6.5 - Compile PHP 5.5 For Threading

This tutorial step you through everything you need to do to get threading working in PHP on CentOS 6.5, and finishes off with a small threaded demonstration. It's quite long, but every step is incredibly simple, so don't be put off.

I see a lot of posts stating that PHP threading is not safe enough for production, but most of these are quite old. There is far more specific information about it actually being safe in the comments below. I will merge this info into this tutorial with time. Special thanks to Krakjoe for pointing this out and providing material.

Compiling Our Own PHP

To be able to perform multithreading (not multiprocessing, thats easy) in PHP, one needs to compile PHP from source with the --enable-maintainer-zts in the configure command.

Just keep running the the following commands one by one.

# Make sure your system is up-to-date!
yum update -y

# Install all the packages we are going to need
yum groupinstall "Development Tools" -y

yum install 
wget \
libxml2-devel \
httpd-devel \
libXpm-devel \
gmp-devel \
libicu-devel \
t1lib-devel \
aspell-devel \
openssl-devel \
bzip2-devel \
libcurl-devel \
libjpeg-devel \
libvpx-devel \
libpng-devel \
freetype-devel \
readline-devel \
libtidy-devel \
libxslt-devel -y

# install epel repo 
http://programster.blogspot.nl/2013/05/centos-6x-install-epel-repository.html
wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
rpm -Uvh epel-* 
rm epel-release-6-8.noarch.rpm -f

# install libmcrypt from epel repo
yum install libmcrypt-devel -y

# Download and extract the PHP source code.
wget -O php-5.5.13.tar.gz http://uk3.php.net/get/php-5.5.13.tar.gz/from/this/mirror
tar --extract --gzip --file php-5.5.13.tar.gz
cd php-5.5.13

Run just one of these commands. You pick!

cp php.ini-development /usr/local/lib/php.ini
cp php.ini-production  /usr/local/lib/php.ini

./configure \
--with-libdir=lib64 \
--prefix=/usr/local \
--with-layout=PHP \
--with-pear \
--with-apxs2 \
--enable-calendar \
--enable-bcmath \
--with-gmp \
--enable-exif \
--with-mcrypt \
--with-mhash \
--with-zlib \
--with-bz2 \
--enable-zip \
--enable-ftp \
--enable-mbstring \
--with-iconv \
--enable-intl \
--with-icu-dir=/usr \
--with-gettext \
--with-pspell \
--enable-sockets \
--with-openssl \
--with-curl \
--with-gd \
--enable-gd-native-ttf \
--with-jpeg-dir=/usr \
--with-png-dir=/usr \
--with-zlib-dir=/usr \
--with-xpm-dir=/usr \
--with-vpx-dir=/usr \
--with-freetype-dir=/usr \
--with-t1lib=/usr \
--with-libxml-dir=/usr \
--with-mysql=mysqlnd \
--with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd \
--enable-soap \
--with-xmlrpc \
--with-xsl \
--with-tidy=/usr \
--with-readline \
--enable-pcntl \
--enable-sysvsem \
--enable-sysvshm \
--enable-sysvmsg \
--enable-shmop \
--enable-maintainer-zts

# compile!
make

Optional Step

You can run this command to check that everything is fine. When I ran this, I got some warnings/errors but the threading still worked. This just emphasised to me that this probably should not be used for production purposes but good for fun.
make test

One last command!

make install

Threading!

This point on is specific to threading, so if you just wanted to roll your own PHP, you can stop here



Install the pthreads extension

pecl install pthreads
Add the following line to your php.ini at
/usr/local/lib/php.ini
extension=pthreads.so

Test It!

Now lets test that threading has actually been implemented. Copy the following script into a file called script.php

<?php

# This is a slightly tweaked version of a script found at below:
# http://forums.devshed.com/php-development-5/multithreading-php-948403.html

# class for sharing data between threads.
class Foo extends Stackable 
{
    public $counter;

    public function __construct()
    {
        $this->counter = 0;
    }

    public function run(){}
}

class Process extends Worker 
{
    private $text = "";

    public function __construct($text, $shared_obj)
    {
        $this->text       = $text;
        $this->shared_obj = $shared_obj;
    }

    public function run()
    {
        while ($this->shared_obj->counter < 100)
        {
            $this->shared_obj->counter++;
            print "thread " . $this->text . ": " . $this->shared_obj->counter . PHP_EOL;
            usleep(rand(10,1000));
        }
    }
}

$foo = new Foo();

$a = new Process("A", $foo);
$a->start();

$b = new Process("B", $foo);
$b->start();

# Wait for the threads to finish before continuing. 
# This simulates waiting for a result that the
# threads come up with between them
$a->join();
$b->join();
print "Done!" . PHP_EOL;

Now run the script with the following command:

php script.php

Explanation

You just spawned 2 threads which shared a single counter. Each thread would increment the counter before going to sleep for a random amount of time. When the counter finally reaches 100, each thread would finish. The program that called the threads waited for them to finish before printing that it has finished. This is the point where you would do something with a value the threads had generated etc. If you run the script multiple times, you will see different output to prove the counter is shared between the threads.


One could launch change the while condition in the threads to "true" and remove the sleep call. Then run htop in another shell/screen and launch the script in order to see two CPU threads run at 100%, further proving the threading aspect. The fact that the counter is shared shows that this is not a case of multiprocessing.

Your Thoughts

Did you have difficulty or do you think something was missing? Perhaps you have more info that you think would benefit others, or you have a tutorial request? Please take the time to comment below.

References

2 comments:

  1. Thread safe interpreters have been in production for more than a decade, it is the default build on Windows, so nearly everyone has actually used it.

    It is extremely misunderstood.

    When you ran make test in the php-src tree, you were testing Zend, not pthreads, or threading (since Zend *never* *ever* creates any threads, for anything).

    https://gist.github.com/krakjoe/6437782

    The actual facts are that threading is as safe as the mod_php DSO built for a worker-mpm installation (the default on windows), or the interpreter built for IIS (which doesn't have a mulch-processing model).

    Feel free to use the content in that article to blog about it ... I'm terrible at blogging, and writing, so I don't do it ...

    ReplyDelete
    Replies
    1. Thanks krakjoe, I'll make sure to add that information to the tutorial. I apologize if my post was misleading about thread safety due to my lack of knowledge. Hopefully by the time others read this the post will have already been updated accordingly.

      I'll ping you on twitter when I update the tutorial and would appreciate it if you would give your feedback again.

      Delete