Initial commit
This commit is contained in:
parent
636ea3ff29
commit
dd6d566b30
255
Thread.php
Normal file
255
Thread.php
Normal file
|
@ -0,0 +1,255 @@
|
|||
<?php
|
||||
/**
|
||||
* Implements threading in PHP
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Threading
|
||||
* @package None
|
||||
* @author Tudor Barbu <miau@motane.lu>
|
||||
* @copyright 2009 MIT
|
||||
* @license http://en.wikipedia.org/wiki/MIT_License MIT License
|
||||
* @link http://blog.motane.lu/2009/01/02/multithreading-in-php/
|
||||
*/
|
||||
|
||||
/**
|
||||
* Thread class
|
||||
*
|
||||
* @category Threading
|
||||
* @package None
|
||||
* @author Tudor Barbu <miau@motane.lu>
|
||||
* @copyright 2009 MIT
|
||||
* @license http://en.wikipedia.org/wiki/MIT_License MIT License
|
||||
* @link http://blog.motane.lu/2009/01/02/multithreading-in-php/
|
||||
*/
|
||||
|
||||
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 isAvailable()
|
||||
{
|
||||
$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 Callback reference
|
||||
*/
|
||||
public function __construct( $runnable = null )
|
||||
{
|
||||
if ( $runnable !== null ) {
|
||||
$this->setRunnable($runnable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the callback
|
||||
*
|
||||
* @param callback $runnable Callback reference
|
||||
*
|
||||
* @return callback
|
||||
*/
|
||||
public function setRunnable( $runnable )
|
||||
{
|
||||
if ( self::isRunnableOk($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 Callback
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isRunnableOk( $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, 'handleSignal' ));
|
||||
$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 or SIGTERM
|
||||
* @param boolean $wait Wait until child has exited
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
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();
|
||||
*
|
||||
* @param integer $signal SIGKILL or SIGTERM
|
||||
* @param boolean $wait Wait until child has exited
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function kill( $signal = SIGKILL, $wait = false )
|
||||
{
|
||||
return $this->stop($signal, $wait);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error's message based on its id
|
||||
*
|
||||
* @param integer $code The error 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 Signal
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handleSignal( $signal )
|
||||
{
|
||||
switch( $signal ) {
|
||||
case SIGTERM:
|
||||
exit( 0 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
- See more at: http://blog.motane.lu/2009/01/02/multithreading-in-php/#sthash.JevFlLcL.dpuf
|
Loading…
Reference in a new issue