这几天遇到一个诡异的问题,同样的代码在一台机器上执行能获得正确结果,但另外一台机器上执行就出错。两台机器的环境本身就是不同的,一个是 CentOS 5,一个是 CentOS 7,使用的 PHP 版本也是不同。深入去分析出错的代码,最终发现是出现在多进程处理部分,Fork 函数出现了问题,新旧系统在 Fork 函数时,父子进程运行的先后顺序是不同的(2.6.32 以前内核是子进程先运行,2.6.32及之后是父进程先运行,并且尝试修改 kernel.sched_child_runs_first 发现也无法改变顺序),在新的机器上会导致代码不能顺利执行下去,跟进去查看,在 Fork.php 中的 start 函数中,子进程在执行完代码后是需要退出的,在新的系统中这里退出就会导致代码无法执行下去,注释掉 exit 虽然能够正常运行,但子进程不退出会带来很多如资源不释放、重复执行等其他问题。最终经过测试,发现将 exit 用 posix_kill(posix_getpid(), SIGTERM)来替代能够正常运行下去且会释放资源,具体代码如下:
function start() { if (!$this->_ipc_is_ok) { die ('Fatal error, unable to create SHM segments for process communications'); } pcntl_signal(SIGCHLD, SIG_IGN); // pcntl_signal(SIGALRM, SIG_IGN); $pid = pcntl_fork(); if ($pid == 0) { // this is the child $this->_isChild = true; sleep(1); // install the signal handler pcntl_signal(SIGUSR1, array($this, "_sig_handler")); /* pcntl_signal(SIGALRM, array($this, "_sig_handler")); pcntl_alarm(1); */ // if requested, change process identity if ($this->_guid != 0) posix_setgid($this->_guid); if ($this->_puid != 0) posix_setuid($this->_puid); $this->setVariable('_has_finished', false); if(func_num_args() > 0) { $args = func_get_args(); call_user_func_array(array($this, 'run'), $args); } else { $this->run(); } $this->setVariable('_has_finished', true); // Added 21/Oct/2003: destroy the child after run() execution // needed to avoid unuseful child processes after execution // exit(0); posix_kill(posix_getpid(), SIGTERM); // replace exit } else { // this is the parent $this->_isChild = false; $this->_running = true; $this->_pid = $pid; } }
参考:
fork()父子进程运行先后顺序