Yii Framework Forum: PHP Simulated Multi-Threading - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

PHP Simulated Multi-Threading Rate Topic: ***** 1 Votes

#1 User is offline   DarkNSF 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 287
  • Joined: 12-November 08
  • Location:Palm Bay, Florida

Posted 23 November 2010 - 03:55 PM

This may or may not come in handy to someone, I found it here: http://blog.motane.l...reading-in-php/


Also.. if there is a cleaner alternative to multi-threading I'm all ears! :)


<?php
/**
 * Implements threading in PHP
 * 
 * @package <none>
 * @version 1.0.0 - stable
 * @author Tudor Barbu <miau@motane.lu>
 * @copyright MIT
 */
class Thread {
    const FUNCTION_NOT_CALLABLE     = 10;
    const COULD_NOT_FORK            = 15;
    
    /**
     * possible errors
     *
     * @var array
     */
    private $errors = array(
        Thread::FUNCTION_NOT_CALLABLE   => 'You must specify a valid function name that can be called from the current scope.',
        Thread::COULD_NOT_FORK          => 'pcntl_fork() returned a status of -1. No new process was created',
    );
    
    /**
     * callback for the function that should
     * run as a separate thread
     *
     * @var callback
     */
    protected $runnable;
    
    /**
     * holds the current process id
     *
     * @var integer
     */
    private $pid;
    
    /**
     * checks if threading is supported by the current
     * PHP configuration
     *
     * @return boolean
     */
    public static function available() {
        $required_functions = array(
            'pcntl_fork',
        );
        
        foreach( $required_functions as $function ) {
            if ( !function_exists( $function ) ) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * class constructor - you can pass
     * the callback function as an argument
     *
     * @param callback $_runnable
     */
    public function __construct( $_runnable = null ) {
    	if( $_runnable !== null ) {
        	$this->setRunnable( $_runnable );
    	}
    }
    
    /**
     * sets the callback
     *
     * @param callback $_runnable
     * @return callback
     */
    public function setRunnable( $_runnable ) {
        if( self::runnableOk( $_runnable ) ) {
            $this->runnable = $_runnable;
        }
        else {
            throw new Exception( $this->getError( Thread::FUNCTION_NOT_CALLABLE ), Thread::FUNCTION_NOT_CALLABLE );
        }
    }
    
    /**
     * gets the callback
     *
     * @return callback
     */
    public function getRunnable() {
        return $this->runnable;
    }
    
    /**
     * checks if the callback is ok (the function/method
     * actually exists and is runnable from the current
     * context)
     * 
     * can be called statically
     *
     * @param callback $_runnable
     * @return boolean
     */
    public static function runnableOk( $_runnable ) {
        return ( function_exists( $_runnable ) && is_callable( $_runnable ) );
    }
    
    /**
     * returns the process id (pid) of the simulated thread
     * 
     * @return int
     */
    public function getPid() {
        return $this->pid;
    }
    
    /**
     * checks if the child thread is alive
     *
     * @return boolean
     */
    public function isAlive() {
        $pid = pcntl_waitpid( $this->pid, $status, WNOHANG );
        return ( $pid === 0 );
        
    }
    
    /**
     * starts the thread, all the parameters are 
     * passed to the callback function
     * 
     * @return void
     */
    public function start() {
        $pid = @ pcntl_fork();
        if( $pid == -1 ) {
            throw new Exception( $this->getError( Thread::COULD_NOT_FORK ), Thread::COULD_NOT_FORK );
        }
        if( $pid ) {
            // parent 
            $this->pid = $pid;
        }
        else {
            // child
            pcntl_signal( SIGTERM, array( $this, 'signalHandler' ) );
            $arguments = func_get_args();
            if ( !empty( $arguments ) ) {
                call_user_func_array( $this->runnable, $arguments );
            }
            else {
                call_user_func( $this->runnable );
            }
            
            exit( 0 );
        }
    }
    
    /**
     * attempts to stop the thread
     * returns true on success and false otherwise
     *
     * @param integer $_signal - SIGKILL/SIGTERM
     * @param boolean $_wait
     */
    public function stop( $_signal = SIGKILL, $_wait = false ) {
        if( $this->isAlive() ) {
            posix_kill( $this->pid, $_signal );
            if( $_wait ) {
                pcntl_waitpid( $this->pid, $status = 0 );
            }
        }
    }
    
    /**
     * alias of stop();
     *
     * @return boolean
     */
    public function kill( $_signal = SIGKILL, $_wait = false ) {
        return $this->stop( $_signal, $_wait );
    }
    
    /**
     * gets the error's message based on
     * its id
     *
     * @param integer $_code
     * @return string
     */
    public function getError( $_code ) {
        if ( isset( $this->errors[$_code] ) ) {
            return $this->errors[$_code];
        }
        else {
            return 'No such error code ' . $_code . '! Quit inventing errors!!!';
        }
    }
    
    /**
     * signal handler
     *
     * @param integer $_signal
     */
    protected function signalHandler( $_signal ) {
        switch( $_signal ) {
            case SIGTERM:
                exit( 0 );
            break;
        }
    }
}

// EOF

1

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users