<?php
 
/**
 
 * PHP_Fork class usage examples
 
 * ==================================================================================
 
 * NOTE: In real world you surely want to keep each class into
 
 * a separate file, then include() it into your application.
 
 * For this examples is more useful to keep all_code_into_one_file,
 
 * so that each example shows a unique feature of the PHP_Fork framework.
 
 * ==================================================================================
 
 * exec_methods.php
 
 * 
 
 * This example shows a workaround to execute methods into the child process.
 
 * Always remember that this is an emulation, and the variable spaces are
 
 * separated between separate processes!
 
 * There're two kinds of methods: PHP_FORK_VOID_METHOD and PHP_FORK_RETURN_METHOD
 
 * the first returns nothing, the second can return any serializable value
 
 * 
 
 * ATTENTION: this feature of PHP_Fork is highly experimental;
 
 * all things are OK until we run such an example, that does nothing and simply
 
 * sleep() all time waiting for a call. Some experiement with real applications
 
 * seems to show that firing the child process with a signal (that is part of the
 
 * workaround...) causes the process to stop execution, and then to repeat ALL the
 
 * run() method after signal caught... This is not an acceptable behaviour and
 
 * should be tested better.
 
 * 
 
 * ==================================================================================
 
 * 
 
 * Copyright (c) 2003-2002 by Luca Mariano ([email protected])
 
 * http://www.lucamariano.it
 
 * 
 
 * This program is free software. You can redistribute it and/or modify
 
 * it under the terms of the GNU General Public License as published by
 
 * the Free Software Foundation; either version 2 of the License.
 
 */
 
// Import of base class
 
require_once ("../Fork.php");
 
// number of executeThreads we want
 
define ("NUM_THREAD", 2);
 
// this is needed as PHP 4.3 in order to use pcntl_signal()
 
declare (ticks = 1);
 
 
/**
 
 * Classes definition. In real world you surely want to keep each class into
 
 * a separate file, then include() it into your application.
 
 * For this examples is more useful to keep all_code_into_one_file
 
 * 
 
 * executeThread class inherit from PHP_Fork and must redefine the run() method
 
 * all the code contained into the run() method will be executed only by the child
 
 * process; all other methods that you define will be accessible both to the parent
 
 * and to the child (and will be executed into the relative process)
 
 */
 
class executeThread extends PHP_Fork {
 
    function executeThread($name)
 
    {
 
        $this->PHP_Fork($name);
 
        $GLOBALS["counter"] = 0;
 
    } 
 
 
    function run()
 
    {
 
        while (true) {
 
            $GLOBALS["counter"]++;
 
            sleep(1);
 
        } 
 
    } 
 
    /**
 
     * A simple method that can be called from the parent process;
 
     * There are 2 types of methods, according to the return value
 
     * 
 
     * PHP_FORK_VOID_METHOD is a method that return no value; a SINGLE array of parameters (or a single parameter) is expected to be passed
 
     * PHP_FORK_RETURN_METHOD is a method that return an array to the calling process
 
     * 
 
     * if nothing is specified, PHP_FORK_VOID_METHOD behaviour is the default
 
     */
 
    function setCounter($val)
 
    {
 
        if ($this->_isChild) {
 
            // do all your stuff here
 
            // remember that only GLOBAL variables can be accessed with this trick, so
 
            // if we need to change the value of the variable $counter from the parent into the
 
            // child (like this code does...) we can't use a class variable ($this->counter),
 
            // neither a local variable...
 
            /**
 
             * * START OF METHOD IMPLEMENTATION *
 
             */
 
            $GLOBALS["counter"] = $val[0];
 
            /**
 
             * * END OF METHOD IMPLEMENTATION *
 
             */
 
        } 
 
        /**
 
         * Never change this line, it requires no adjustments...
 
         */
 
        else return $this->register_callback_func(func_get_args(), __FUNCTION__);
 
    } 
 
 
    function getCounter($params)
 
    {
 
        if ($this->_isChild) {
 
            return $GLOBALS["counter"];
 
        } else return $this->register_callback_func(func_get_args(), __FUNCTION__);
 
    } 
 
} 
 
 
/**
 
 * Functions used by the console
 
 */
 
function _getInputCLI()
 
{
 
    $opt = _read();
 
    $opt = strtoupper (trim($opt));
 
    return $opt;
 
} 
 
 
function _read()
 
{
 
    $fp = fopen("php://stdin", "r");
 
    $input = fgets($fp, 255);
 
    fclose($fp);
 
 
    return $input;
 
} 
 
 
/**
 
 * Main program. Bring up two instances of the executeThread class that
 
 * runs concurrently. It's a multi-thread app with a few lines of code!!!
 
 * executeThread does nothing interesting, it simply has a counter and increment
 
 * this counter each second... (see class definition at top of this file)
 
 */
 
for ($i = 0;$i < NUM_THREAD;$i++) {
 
    $executeThread[$i] = &new executeThread ("executeThread-" . $i);
 
    $executeThread[$i]->start();
 
    echo "Started " . $executeThread[$i]->getName() . " with PID " . $executeThread[$i]->getPid() . "...\n";
 
} 
 
 
print "This is the main process.\nPress [X] to terminate, [S] to reset all counters, [G] to get the actual value of counters.\n";
 
 
/**
 
 * Console simple listener
 
 */
 
while (true) {
 
    echo ">";
 
 
    $opt = _getInputCLI();
 
    echo "\n";
 
    switch ($opt) {
 
        case "X": 
 
            // stops all threads
 
            for ($i = 0;$i < NUM_THREAD;$i++) {
 
                $executeThread[$i]->stop();
 
                echo "Stopped " . $executeThread[$i]->getName() . "\n";
 
            } 
 
            exit;
 
            break;
 
 
        case "S": 
 
            // setCounter is a PHP_FORK_VOID_METHOD
 
            // it only need a paramenter (an array containing data that must be passed to child)
 
            for ($i = 0;$i < NUM_THREAD;$i++) {
 
                $executeThread[$i]->setCounter(0);
 
            } 
 
            break;
 
 
        case "G": 
 
            // getCounter is a method that reads the value of the thread counter
 
            // so getCounter is a RETURN_METHOD and MUST be called with 2 parameters;
 
            // the first is an array of data that must be passed to the method, the second is
 
            // the constant (RETURN_METHOD)
 
            for ($i = 0;$i < NUM_THREAD;$i++) {
 
                echo $executeThread[$i]->getName() . " returns " . $executeThread[$i]->getCounter('', PHP_FORK_RETURN_METHOD) . "\n";
 
            } 
 
 
            break;
 
    } 
 
} 
 
 
?>
 
 
 |