本人在windows下创建多进程的研究,唯一缺点,主进程所在终端关闭则所有子进程全部关闭。原理是通过proc_open创建多进程,通过环境变量识别父子进程,还能通过proc_open进行父子进程通信
<?php
namespace EasyTask;
use \Exception as Exception;
/**
* Class Wpc
* @package EasyTask
*/
class Wpc
{
/**
* 进程实例
* @var resource
*/
private $instance = null;
/**
* 环境变量
* @var null
*/
private $env = null;
/**
* 进程管道
* @var null
*/
private $pipes = [];
/**
* 进程工作目录
* @var null
*/
private $workDir = null;
/**
* 进程文件
* @var null
*/
private $filename = '';
/**
* 进程执行参数
* @var null
*/
private $argument = '';
/**
* 标准输入输出描述符
* @var array
*/
private $stdStruct = [];
/**
* 设置环境变量
* @param array $env
* @return $this
*/
public function setEnv($env)
{
$this->env = $env;
return $this;
}
/**
* 设置进程文件
* @param string $filename
* @return $this
* @throws Exception
*/
public function setFile($filename)
{
$filename = realpath($filename);
if (!file_exists($filename))
{
throw new Exception("the file:{$filename} is not exist");
}
$this->filename = $filename;
return $this;
}
/**
* 设置进程参数
* @param string $argument
* @return $this
*/
public function setArgument($argument)
{
$argument = (string)$argument;
$this->argument = $argument;
return $this;
}
/**
* 设置进程工作目录
* @param string $path
* @return $this
* @throws Exception
*/
public function setWorkDir($path)
{
$path = realpath($path);
if (!is_dir($path))
{
throw new Exception("the path:{$path} is not exist");
}
$this->workDir = $path;
return $this;
}
/**
* 设置标准输入输出文件描述符
* @param array $struct
* @return $this
*/
public function setStdStruct($struct)
{
$this->stdStruct = $struct;
return $this;
}
/**
* 获取进程ID
* @return int|false
*/
public function getPid()
{
if (is_resource($this->instance))
{
$status = proc_get_status($this->instance);
return !empty($status['pid']) ? $status['pid'] : false;
}
return false;
}
/**
* 获取程是否正在运行
* @return bool
*/
public function getIsRunning()
{
if (is_resource($this->instance))
{
$status = proc_get_status($this->instance);
return !empty($status['running']) ? $status['running'] : false;
}
return false;
}
/**
* 启动进程
* @return int 进程id
* @throws
*/
public function start()
{
if (!$this->stdStruct)
{
throw new Exception('Please set the file descriptor');
}
$this->instance = proc_open("$this->filename $this->argument", $this->stdStruct, $this->pipes, $this->workDir, $this->env, ['bypass_shell' => true]);
if (!$this->instance)
{
throw new Exception('failed to create process through proc_open');
}
return $this->getPid();
}
/**
* 停止进程
* @param bool $force 是否强制退出
*/
public function stop($force = false)
{
if (is_resource($this->instance))
{
$this->closePipes();
if (!$force)
{
proc_close($this->instance);
}
else
{
proc_terminate($this->instance);
}
}
}
/**
* 关闭管道
*/
private function closePipes()
{
if (is_resource($this->instance))
{
foreach ($this->pipes as $pipe)
{
if (is_resource($pipe))
{
fclose($pipe);
}
}
}
}
}