需要介绍的几个函数
- fork() 允许一个进程创建一个子进程,子进程获得父进程的栈,数据段,堆和执行文本段
- exit(status) 终止一个进程,将进程占据的所有资源释放
- wait(&status) 如果子进程尚未调用exit()终止,那么wait()会挂起父进程直到子进程终止,子进程的终止状态通过wait函数的status参数返回
fork
- fork函数对其调用后将存在两个进程,并且每个进程都会从fork的返回处继续执行。在不同的进程中fork的返回值不同,父进程中返回创建的子进程ID,子进程中返回0
- fork调用后系统会调度哪个进程,是无法确定的
public function createProcess($count)
{
for ($liLoop = 0; $liLoop < $count; $liLoop++) {
$pid = pcntl_fork();
switch ($pid) {
case -1:
echo "something error!\r\n";
break;
case 0:
$childPid = posix_getpid();
echo "I am child pid:" . $childPid . "\r\n";
sleep(5);
break;
default:
$this->mChildProcess[$pid] = true ;
$this->mMasterPID = posix_getpid();
echo "I am parent pid:" . posix_getpid() . "\r\n";
break;
}
}
$currentPid = posix_getpid();
if($currentPid == $this->mMasterPID)
{
while (!empty($this->mChildProcess)) {
$exitChild = pcntl_wait($exit);
if ($exitChild > 0) {
echo "child ".$exitChild." finish task!\r\n";
unset($this->mChildProcess[$exitChild]);
}
}
echo posix_getpid() ." Experiment Finish\r\n";
}
}
进程之间的文件共享
- 执行fork时,子进程会获得父进程所有文件描述符的副本.这些副本的创建方式类似于dup(),这也意味着子进程中的描述符均指向相同的打开的文件句柄。举例来说如果子进程更新了文件偏移量,会影响到父进程中相应的描述符
- 在使用fork调用后,如果不需要对文件描述符的共享方式,需要注意两点:1.令父子进程使用不同的描述符。2.各自关闭不再使用的描述符
public function shareFileDescriptor()
{
$file = fopen($this->mShareFile,"r");
echo "before fork the current offset is:".ftell($file)."\r\n";
$pid = pcntl_fork();
switch ($pid) {
case -1:
echo "something error!\r\n";
break;
case 0:
$childPid = posix_getpid();
fseek($file,5);
echo "in child we modify the offset the current offset is:".ftell($file)."\r\n";
break;
default:
sleep(5);
$content = fread($file,5);
echo "in parent we read :".$content."\r\n";
echo "in parent, child has modified the offset the current offset is:".ftell($file)."\r\n";
break;
}
}
fork的内存语义
- 内核将每一进程的代码标记位只读,使进程无法修改自身代码。这样,父子进程可共享同一代码段。系统调用fork在子进程创建代码段时,其构建的一系列进程级页表均指向与父进程相同的福利内存页帧
- 对于父进程数据段、堆段、和栈段中的各页,内核采用写时复制技术
进程间通讯