php进程控制

来源:互联网 发布:linux查看卡死进程命令 编辑:程序博客网 时间:2024/06/03 14:54

简介

PHP的进程控制支持实现了Unix方式的进程创建, 程序执行, 信号处理以及进程的中断。 进程控制不能被应用在Web服务器环境,当其被用于Web服务环境时可能会带来意外的结果。

这份文档用于阐述每个进程控制函数的通常用法。关于Unix进程控制的更多信息建议您查阅 系统文档中关于fork(2),waitpid(2),signal(2)等的部分或更全面的参考资料比如 《Unix环境高级编程》(作者:W. Richard Stevens,Addison-Wesley出版)。

PCNTL现在使用了ticks作为信号处理的回调机制,ticks在速度上远远超过了之前的处理机制。 这个变化与“用户ticks”遵循了相同的语义。您可以使用 declare() 语句在程序中指定允许发生回调的位置。这使得我们对异步事件处理的开销最小化。在编译PHP时 启用pcntl将始终承担这种开销,不论您的脚本中是否真正使用了pcntl。

有一个调整是PHP 4.3.0之前的所有pcntl脚本要使其工作,要么在期望允许回调的(代码)部分使用 declare() ,要么使用 declare()新的全局语法 使其在整个脚本范围有效。

Note此扩展在 Windows 平台上不可用。



reject note add a note add a noteUser Contributed Notes 简介 - [1 notes]
up
down
0
sean dot kelly at mediatile dot com
1 year ago
The following statement left me searching for answers for about a day before I finally clued in:

"Process Control should not be enabled within a web server environment and unexpected results may happen if any Process Control functions are used within a web server environment."

At least for PHP 5.3.8 which I am using, and who knows how far back, it's not a matter of "should not", it's "can not". Even though I have compiled in PCNTL with --enable-pcntl, it turns out that it only compiles in to the CLI version of PHP, not the Apache module. As a result, I spent many hours trying to track down why function_exists('pcntl_fork') was returning false even though it compiled correctly. It turns out it returns true just fine from the CLI, and only returns false for HTTP requests. The same is true of ALL of the pcntl_*() functions.



安装

在PHP中进程控制支持默认是关闭的。您需要使用 --enable-pcntl 配置选项重新编译PHP的 CGI或CLI版本以打开进程控制支持。

Note:

当前,这个模块没有非Unix平台可用的函数(即非Unix类系统不支持此模块)。



reject note add a note add a noteUser Contributed Notes 安装 - [1 notes]
up
down
0
diogo-nechtan at tagon8inc dot com
9 months ago
Manual installation on Mountain Lion (OS X 10.8)

first: Download the php source
(e.g. $ wget http://br.php.net/get/php-5.3.15.tar.gz/from/this/mirror)

nechtan$ sudo su
sh-3.2# tar -zxvf php-5.3.15.tar.gz
sh-3.2# cd php-5.3.15/ext/pcntl/
sh-3.2# phpize && ./configure && make install
sh-3.2# echo "extension=pcntl.so" >> /etc/php.ini
sh-3.2# apachectl restart

checking if everything is ok.

sh-3.2# php -m | grep pcntl
pcntl

testing pcntl with Facebook's PHP shell:
http://www.phpsh.org/
add a note add a note




这个示例用于产生一个守护进程并可以通过信号处理进行关闭。

Example #1 进程控制示例

<?php
//定义ticks
declare(ticks=1);

//产生子进程分支
$pid pcntl_fork();
if (
$pid == -1) {
     die(
"could not fork"); //pcntl_fork返回-1标明创建子进程失败
} else if ($pid) {
     exit(); 
//父进程中pcntl_fork返回创建的子进程进程号
} else {
     
// 子进程pcntl_fork返回的时0
}

// 从当前终端分离
if (posix_setsid() == -1) {
    die(
"could not detach from terminal");
}

// 安装信号处理器
pcntl_signal(SIGTERM"sig_handler");
pcntl_signal(SIGHUP"sig_handler");

// 执行无限循环任务
while (1) {

    
// do something interesting here

}

function 
sig_handler($signo
{

     switch (
$signo) {
         case 
SIGTERM:
             
// 处理中断信号
             
exit;
             break;
         case 
SIGHUP:
             
// 处理重启信号
             
break;
         default:
             
// 处理所有其他信号
     
}

}

?>





PCNTL 函数

参见

参考一下 POSIX functions 对有助于理解使用。

Table of Contents

  • pcntl_alarm — 为进程设置一个alarm闹钟信号
  • pcntl_exec — 在当前进程空间执行指定程序
  • pcntl_fork — 在当前进程当前位置产生分支(子进程)。译注:fork是创建了一个子进程,父进程和子进程 都从fork的位置开始向下继续执行,不同的是父进程执行过程中,得到的fork返回值为子进程 号,而子进程得到的是0。
  • pcntl_getpriority — 获取任意进程的优先级
  • pcntl_setpriority — 修改任意进程的优先级
  • pcntl_signal_dispatch — 调用等待信号的处理器
  • pcntl_signal — 安装一个信号处理器
  • pcntl_sigprocmask — 设置或检索阻塞信号
  • pcntl_sigtimedwait — 带超时机制的信号等待
  • pcntl_sigwaitinfo — 等待信号
  • pcntl_wait — 等待或返回fork的子进程状态
  • pcntl_waitpid — 等待或返回fork的子进程状态
  • pcntl_wexitstatus — 返回一个中断的子进程的返回代码
  • pcntl_wifexited — 检查状态代码是否代表一个正常的退出。
  • pcntl_wifsignaled — 检查子进程状态码是否代表由于某个信号而中断
  • pcntl_wifstopped — 检查子进程当前是否已经停止
  • pcntl_wstopsig — 返回导致子进程停止的信号
  • pcntl_wtermsig — 返回导致子进程中断的信号


pcntl_alarm><
[edit] Last updated: Fri, 03 May 2013
 
reject note add a note add a noteUser Contributed Notes PCNTL 函数 - [18 notes]
up
down
1
kevin at vanzonneveld dot net
4 years ago
If you want to create a daemon in PHP, consider using System_Daemon http://pear.php.net/package/System_Daemon

Install it like this:
pear install -f system_daemon

Then use it like this:
<?php
// Include PEAR's Daemon Class
require_once "System/Daemon.php";

// Bare minimum setup
System_Daemon::setOption("appName""mydaemonname");

// Spawn Deamon!
System_Daemon::start();

// Your PHP Here!
while (true) {
    
doTask();
}

// Stop daemon!
System_Daemon::stop();
?>

More examples can be found inside the PEAR package.
up
down
0
m dot quinton at gmail dot com
5 years ago
a nice example of a class framework to manage tasks using pcntl_fork.

<?php

/**
 * author : Marc Quinton / April 2008.
 *
 *  a simple task management framework using pcntl_fork, pcntl_wait.
 *
 *  - see at bottom for a sample usage.
 *  - you shoud overring Task class (SleepingClass is an example), and manage them in a pool, using taskManager
 */

error_reporting(E_ALL);

class 
Task {

    protected 
$pid;
    protected 
$ppid;

    function 
__construct(){
    }

    function 
fork(){
        
$pid pcntl_fork();
        if (
$pid == -1)
            throw new 
Exception ('fork error on Task object');
        elseif (
$pid) {
            
# we are in parent class
            
$this->pid $pid;
            
# echo "< in parent with pid {$his->pid}\n";
        
} else{
            
# we are is child
            
$this->run();
        }
    }

    function 
run(){
        
# echo "> in child {$this->pid}\n";
        # sleep(rand(1,3));
        
$this->ppid posix_getppid();
        
$this->pid posix_getpid();
    }

    
# call when a task in finished (in parent)
    
function finish(){
        echo 
"task finished {$this->pid}\n";
    }

    function 
pid(){
        return 
$this->pid;
    }
}

class 
SleepingTask extends Task{
    function 
run(){
        
parent::run();
        echo 
"> in child {$this->pid}\n";

        
# print_r($this);

        
sleep(rand(1,5));
        echo 
"> child done {$this->pid}\n";
        exit(
0);
    }
}

class 
TaskManager{

    protected 
$pool;

    function 
__construct(){
        
$this->pool = array();
    }

    function 
add_task($task){
        
$this->pool[] = $task;
    }

    function 
run(){

        foreach(
$this->pool as $task){
            
$task->fork();
        }

        
# print_r($this);
        # sleep(60);

        
while(1){
            echo 
"waiting\n";
            
$pid pcntl_wait($extra);
            if(
$pid == -1)
                break;

            echo 
": task done : $pid\n";
            
$this->finish_task($pid);
        }

        echo 
"processes done ; exiting\n";
        exit(
0);
    }

    function 
finish_task($pid){
        if(
$task $this->pid_to_task($pid))
            
$task->finish();
    }

    function 
pid_to_task($pid){
        foreach(
$this->pool as $task){
            if(
$task->pid() == $pid)
                return 
$task;
        }
        return 
false;
    }
}

$manager = new TaskManager();

for(
$i=$i<10 $i++)
    
$manager->add_task(new SleepingTask());

$manager->run();

?>
up
down
0
registrazioni at XSPAMX dot tassetti dot net
5 years ago
(PHP 5.2.4) 

This is an example of multithreading keeping different connections to a mysql database: when children exit they close the connection and others can't use it any more generating problems. In this example I used variable variables to make a different connection per each child. 

This scripts loops forever with one mother detached from the terminal and five children 'named' from 1 to 5. When one children sees it's name in the database (one table 'test.tb' with only one field 'test') he lets himself die. To kill children insert their value in the db. The mother suicides only when all children are dead.

What a sad but interesting story...

    $npid = pcntl_fork(); // DETACH FROM TERMINAL AND BE REAPED BY INIT

    if ($npid==-1) die("Error: impossible to pcntl_fork()\n");
    else if ($npid) exit(0); // THE GRANPA DIES
    else // MOTHER GOES ON TO MAKE CHILDREN
    {
        $children = 5;
        for ($i=1; $i<=$children; $i++)
        {
            $pid = pcntl_fork();
            if ($pid==-1) die("Error: impossible to pcntl_fork()\n");
            else if ($pid)
            {
                 $pid_arr[$i] = $pid;
            }
            if (!$pid) // CHILDREN
            {
                global $vconn;
                $vconn = "vconn$i";
                global $$vconn;
                $$vconn = @mysql_connect("mydbhost","mydbuser","mydbpwd");
                if (!($$vconn)) echo mysql_error();
                if (!($$vconn)) exit;

                while (1)
                {
                    $query = "SELECT test FROM test.tb";
                    $rs = mysql_query($query,$$vconn);
                    $rw = mysql_fetch_row($rs);
                    if ($rw[0]==$i) exit;
                    else
                    {
                        echo "Database is $rw[0] and I am $i, it's not my time, I will wait....\n";
                        sleep(1);
                    }
                }
            }
        }

        foreach ($pid_arr as $pid)
        {
            // we are the parent and we wait for all children to die
            pcntl_waitpid($pid, $status);
        }
        echo "All my children died, I will suicide...\n";
        exit();
    }
up
down
0
flyingguillotine1968 at yahoo dot com
5 years ago
ok, heres what ya do to handle child process's ... :> 

you want to pfork your main program, and let it exit, 
allowing the new child to become the main program (parent process).

example psudo code : 
main program start;
     ....
     if pfork'd child ok
          then exit ;

    // now your new child process is in control... 
    // use a signal handler to make it exit (sigkill or sigterm probably)
    // when this new process pforks, store the new child PID's in an
    // array.   when your process  catch's the sigterm  signal
    // loop thru the array of its child PID's sending each child
    // sigkill , then call  pwait on them to wait for them to exit.
    // this will make sure any child process are cleaned up ok
    // THEN .. now here's the trick.... 
    // reset yer sigterm handler BACK to its original default handler, 
   // thennnnn   raise sigterm , main program will exit ok now tooooo :> 

  
example: 
when your pfork'd main process gets sigterm ... then do something 
like this : 

foreach ($this->pForkList as $kiddie) {
$deadPID    = 0;
$this->sendSignal(SIGKILL,$kiddie);
do {
$deadPID = pcntl_waitpid(-1,WNOHANG);
if ($deadPID > 0) {
// kiddie has exited now ... 
unset($this->pForkList[ array_search($deadPID,$this->pForkList)]);
break;
} // end if
} while ($deadPID == 0);

} // end for

// now reset sigterm ... 
$this->signalSet($sigNum,SIG_DFL);
// RAISE sigterm now ... 
$this->sendSignal(SIGTERM,$this->myPID);

this will allow your main process and all its child process's to exit properly and not leave and zombies or other bad stuff behind !
up
down
0
kementeusNOSPAM at gmail dot com
6 years ago
In the example of the documentation we need to put the pctnl_signal statements BEFORE the while loop.

In that way we can execute whatever we put in the signal handler functions.
up
down
0
corychristison at lavacube dot com
8 years ago
An easier way than what was first suggested in the first comment, to retrieve what signal your application is being sent would be to use get_defined_constants() to list all constants, loop through and strip out those that are not signals, and to check if it matches the value.

Here is my code for doing this, written for PHP5 only.
<?php

// php5 Specfic

function pcntl_sig_identify $sig_no ) {
    
$get_constants get_defined_constants(true);
    
$pcntl_contstants $get_constants["pcntl"];
    
$keys array_keys$pcntl_contstants );
      foreach(
$keys as $key){
        if(
strstr($key"SIG") && !strstr($key"_") && $pcntl_contstants[$key] == $sig_no){
      return 
$key;
    }
      } 
// end loop
// end function pcntl_sig_identify

// 
// This example will output "SIGTERM"
//

print pcntl_sig_identify(15) . "\n";

?>
up
down
0
andy at cbeyond dot net
8 years ago
Suppose you want to fork off children to handle a few hundred different targets (like, say, SNMP polling, but that's just one example).  Since you don't want to fork-bomb yourself, here's one method of limiting the number of children you have in play at any one time:

#!/usr/bin/php -q
<?php
declare(ticks 1);

$max=10;
$child=0;

// function for signal handler
function sig_handler($signo) {
  global 
$child;
  switch (
$signo) {
    case 
SIGCHLD:
      echo 
"SIGCHLD received\n";
      
$child -= 1;
  }
}

// install signal handler for dead kids
pcntl_signal(SIGCHLD"sig_handler");

for (
$i=1;$i<=20;$i++) {
        while (
$child >= $max) {
                
sleep(5); echo "\t Maximum children allowed\n";
                }
        
$child++;
        
$pid=pcntl_fork();
        if (
$pid == -1) {
                die(
"could not fork");
        } else if (
$pid) {
                
// we are the parent
        
} else {
                
// we are the child
                
echo "child number $i\n";
                
// presumably doing something interesting
                
sleep(15);
                exit;
        }
}
up
down
0
Anonymous
9 years ago
in example 1, i found unless i create function sig_handler _BEFORE_ pcnt_signal, it wouldnt work.. and would just fall to the floor bleeding to death

(note for people having these kinda probs)
up
down
0
cameronNO_SPAM at tripdubdev dot com
9 years ago
I'm currently working on some code for this, but in case I forget to come back to post to the board, or in case it takes me a while, why not just have a separate background job running (started up via the shell) that tracks which sockets are available to clients ?  Then all you'd have to do is communicate with the one job (or perhaps its own mini-server) run in the background that keeps an array of the available sockets for the server.  This seems the most natural alternative since PHP disclaims that process control functionality should not be used in a web-server environment.  I would hate to build a server, especially one with high traffic, that had to run through a loop in order to find an available socket.
up
down
0
luca dot mariano at email dot it
9 years ago
Hi folks,
if someone uses PHP-CLI onWin32 and wants to experiment the PCNTL stuff, I've packed a binary version of PHP with built-in pcntl, shmop, sysvshm and other typical Unix extensions... (thanks to Cygwin DLLs).
Download it: http://phplet.sf.net/modules.php?name=Web_Links&l_op=visit&lid=4
up
down
0
jeremy at nirvani dot net
9 years ago
#!/usr/local/bin/php -q
<?php

# Jeremy Brand <jeremy@nirvani.net>
# http://www.nirvani.net/

# ./configure --enable-pcntl --enable-sigchild
# make
# make install

# This code example shows how to use a script to do multiprocessing.  Each time
# this script is ran, the result is 5 (in this example) processes running to
# accomplish a specified task.

# Examples could be a messaging queue.  You could get the number of messages in
# a queue and handle any or all of them asynchronously.

# Get the number of children you want to be born by running this
# script once.
$children 5# likely a function call here.

for ($i=1$i<=$children$i++)
{

  
$pid pcntl_fork();
  if (
$pid == -1)
  {
    die(
"could not fork\n");
  }
  else if (
$pid)
  {
    
# If we are the parent, we did our job of giving birth,
    # now lets finish our job and die!
    
exit(0);
  }
  else
  {
    
# Since we are the child, fork so that init will become our parent.  Init
    # is good at wait()ing on children - ie: reaping.
    
$cpid pcntl_fork();
    if (
$cpid == -1)
    {
      die(
"could not fork in child process\n");
    }
    if (!
$cpid)
    {
      
# We have now forked off from our parent and also are not waiting on any
      # other children to process, however other children are running
      # simutaniously to us.  Make sure the code you write here is safe to run
      # in this environment of multiprocessing - ie: proper locking, etc.
      # Write the custom code here that you want to multiprocess.

      # ADD CODE HERE TO MULTIPROCESS
      
print "we are child number $i\n";

      
# Don't forget to exit after the child processing is done.  Certainly
      # change this exit code if you need to however.
      
exit(0);
    }
  }
}

?>
up
down
0
David Koopman
9 years ago
I had a hard time finding a complete example of using PHP as a multi-process (or multi-threaded - I don't understand the difference in these two terms) daemon using connection pooling.  I put pieces of the puzzle together and came up with the program below.  I hope it helps someone.  Notes about making this work:

1) I rebuilt PHP on my machine with these config options:
./configure --enable-sockets --enable-pcntl --enable-sigchild
make
make install

2) I have problems when tried to handle SIGTERM and SIGHUP myself, so I removed these from my code, don't use them unless you have a special need for this:
pcntl_signal(SIGTERM, "sig_handler");
pcntl_signal(SIGHUP, "sig_handler");

What I do is: 
1. start the program, then fork to detach from the terminal (kill the parent and make the child the session leader).

2. bind to address and port and start listening.

3. fork $poolNum times, creating $poolNum children (this is the pool of daemons running.  The children handle the incoming connections).

4. keep the parent process running in a loop, constantly checking to see if it should create a new child.  It will always keep $poolNum spare children ready (as long as the total pooled connections doesn't exceed $maxDaemon).  As connections come in, more children are spawned. 

5. When a new connection comes in, it is handed off to the first child.  This child then sends a SIGUSR1 signal back to the parent.  The parent has a signal handler for SIGUSR1, which will increment the $numActive variable by one.  The loop that is running (see 4 above) will note the increment in $numActive and automatically create a new child process to keep the process pool going.

I have to post the code in the next note, the note engine on this site won't allow such a long note to be posted, but I think this code example is well worth a comment on this...
up
down
0
schst at php dot net
9 years ago
To get rid of the zombies when child processes terminate you do not have to write a lot of code that uses complex stuff like message queues.
Instead you only set a signal handler:

pcntl_signal(SIGCHLD, SIG_IGN);

Stephan
up
down
0
Patrice Levesque
9 years ago
So, you want to create multiple child processes and don't want any zombies, don't you?

You can use IPC to achieve just that.  Every child that is spawned has to tell its parent that time has come for him to be terminated.  So, yes, zombies will be created, but once in a while the parent will 'clean up' after his kids.  Code:

<?php
  
declare(ticks 1);
  
// create a IPC message queue
  
$msgqueue msg_get_queue(ftok("/tmp/php_msgqueue.stat"'R'),0666 IPC_CREAT);
  
// loop for 1000 children 
  
for ($c 0$c 1000$c++) {
    
// fork
    
$pcid pcntl_fork();
    if (
$pcid == -1) {
      die(
"Could not fork!");
    }
    elseif (
$pcid) { // we are the parent, look for zombie kids and terminate 'em
      // look in the IPC message queue if there are any entries
      
$currentqueue msg_stat_queue($msgqueue);
      
$n $currentqueue['msg_qnum']; // number of messages (number of kids to terminate)
      
if ($n 0) {
        echo 
"There are $n kids to terminate.\n";
        for (
$i 0$i $n$i++) {
          
// pop the kid's PID from the IPC message queue
          
if (!msg_receive ($msgqueue1$msg_type16384$msgtrue0$msg_error)) {
            echo 
"MSG_RECV ERROR: $errmsg \n"// something has gone wrong
          
}
          else {
            
pcntl_waitpid($msg$tmpstat0); // terminate kid for real.
          
};
        };
      };
    }
    else { 
// we are the child!
      
if (!posix_setsid()) { die ("Could not detach"); }; // detach
      
echo "I am child number $c\n";
      
sleep(5); // do something useful
      // tell dad I'm finished via IPC: send him my PID
      
if (!msg_send($msgqueue1posix_getpid(), truetrue$errmsg)) {
        echo 
"MSG_SEND ERROR: $errmsg \n";
      };
      exit(); 
// become a zombie until dad kills me                            
    
};
  };
?>
up
down
0
van[at]webfreshener[dot]com
10 years ago
Forking your PHP daemon will cause it to zombie on exit. 

...or so I've seen on: 
FreeBSD (PHP4.2.x) 
Debian (PHP4.3.0-dev) 
Darwin (PHP4.3.0-dev) 

This was tested with the example code above and other scripts created for evaluation. 

Seems adding --enable-sigchild to your configure will get rid of the problem. 

Hope that saves some hair tearing :]
up
down
0
keksov[at]gmx.de
10 years ago
You have to use socket_select before socket_accept, so your code will wait for connection with select. socket_select can be interrupted by signals easily. Below is an example from my library (methods of class TNetSocket):
  //-- select
  function select($aread=NULL,$awrite=NULL,$aexcept=NULL,$timeout=NULL)
  {
    while(1)
    {
      $res="";
      $res=socket_select($aread, $awrite, $aexcept, $timeout);

      // if errno===0 it means what select was interrrupted by SysV signal
      if($res===false && socket_last_error($this->socket())!==0)
      { // error occured, interrupted not by a signal
        $this->set_socket_error(__LINE__);
        return(false);
      }
      break;
    }
    return(true);
  }

  //-- accept, wait for incomming connection
  function accept()
  {
    $this->clear_socket_error();
    $this->set_io_socket(_SOCKET_);

    $socket=$this->socket();
    $aread=array($socket);
    if ($this->select($a=&$aread)===false)
      return(false);

    $child_socket=socket_accept($this->socket);
    if($child_socket <= 0)
    { // error occured
      $this->set_socket_error(__LINE__);
      return(false);
    }

    $this->child_socket=$child_socket;
    $this->sockets[_CHILD_SOCKET_]=&$this->child_socket;
    $this->set_io_socket(_CHILD_SOCKET_);

    $a=&$this->peername;
    $res=socket_getpeername($child_socket,$a);

    if($res <= 0)
    { // error occured
      $this->set_socket_error(__LINE__);
      return(false);
    }

    $this->get_address_and_port(_CHILD_SOCKET_);
    TLogManager::phpserv("Connection accepted. ADDRESS $this->address, PORT $this->port","net_socket",__FILE__,__LINE__);

    $this->connected=true;
    return(true); // return new object of TNetSocket type
  }
up
down
0
daniel[at]lorch.cc
11 years ago
This piece of code helped me to find out what signals are being sent to my process:

function sig_identify($signo) {
  switch($signo) {
    case SIGFPE:    return 'SIGFPE';
    case SIGSTOP:   return 'SIGSTOP';
    case SIGHUP:    return 'SIGHUP';
    case SIGINT:    return 'SIGINT';
    case SIGQUIT:   return 'SIGQUIT';
    case SIGILL:    return 'SIGILL';
    case SIGTRAP:   return 'SIGTRAP';
    case SIGABRT:   return 'SIGABRT';
    case SIGIOT:    return 'SIGIOT';
    case SIGBUS:    return 'SIGBUS';
    case SIGPOLL:   return 'SIGPOLL';
    case SIGSYS:    return 'SIGSYS';
    case SIGCONT:   return 'SIGCONT';
    case SIGUSR1:   return 'SIGUSR1';
    case SIGUSR2:   return 'SIGUSR2';
    case SIGSEGV:   return 'SIGSEGV';
    case SIGPIPE:   return 'SIGPIPE';
    case SIGALRM:   return 'SIGALRM';
    case SIGTERM:   return 'SIGTERM';
    case SIGSTKFLT: return 'SIGSTKFLT';
    case SIGCHLD:   return 'SIGCHLD';
    case SIGCLD:    return 'SIGCLD';
    case SIGIO:     return 'SIGIO';
    case SIGKILL:   return 'SIGKILL';
    case SIGTSTP:   return 'SIGTSTP';
    case SIGTTIN:   return 'SIGTTIN';
    case SIGTTOU:   return 'SIGTTOU';
    case SIGURG:    return 'SIGURG';
    case SIGXCPU:   return 'SIGXCPU';
    case SIGXFSZ:   return 'SIGXFSZ';
    case SIGVTALRM: return 'SIGVTALRM';
    case SIGPROF:   return 'SIGPROF';
    case SIGWINCH:  return 'SIGWINCH';
    case SIGPWR:    return 'SIGPWR';
  }
}

function sig_handler($signo) {
  echo "Caught " . sig_identify($signo) . " (" . $signo  . ") on " . posix_getpid() . "\n";
}

pcntl_signal(SIGFPE, "sig_handler");
pcntl_signal(SIGHUP, "sig_handler");
// pcntl_signal(SIGINT, "sig_handler");
pcntl_signal(SIGQUIT, "sig_handler");
pcntl_signal(SIGILL, "sig_handler");
pcntl_signal(SIGTRAP, "sig_handler");
pcntl_signal(SIGABRT, "sig_handler");
pcntl_signal(SIGIOT, "sig_handler");
pcntl_signal(SIGBUS, "sig_handler");
pcntl_signal(SIGPOLL, "sig_handler");
pcntl_signal(SIGSYS, "sig_handler");
pcntl_signal(SIGCONT, "sig_handler");
pcntl_signal(SIGUSR1, "sig_handler");
pcntl_signal(SIGUSR2, "sig_handler");
pcntl_signal(SIGSEGV, "sig_handler");
pcntl_signal(SIGPIPE, "sig_handler");
pcntl_signal(SIGALRM, "sig_handler");
pcntl_signal(SIGTERM, "sig_handler");
pcntl_signal(SIGSTKFLT, "sig_handler");
pcntl_signal(SIGCHLD, "sig_handler");
pcntl_signal(SIGCLD, "sig_handler");
pcntl_signal(SIGIO, "sig_handler");
pcntl_signal(SIGTSTP, "sig_handler");
pcntl_signal(SIGTTIN, "sig_handler");
pcntl_signal(SIGTTOU, "sig_handler");
pcntl_signal(SIGURG, "sig_handler");
pcntl_signal(SIGXCPU, "sig_handler");
pcntl_signal(SIGXFSZ, "sig_handler");
pcntl_signal(SIGVTALRM, "sig_handler");
pcntl_signal(SIGPROF, "sig_handler");
pcntl_signal(SIGWINCH, "sig_handler");
pcntl_signal(SIGPWR, "sig_handler");

I commented out SIGNIT, as it is the signal which is sent to your process when you press CTRL-C. If you catch this signal, you must handle it properly:

function sig_handler($signo) {
  switch($signo) {
    case SIGINT:
      // customized cleanup code
      exit; // now exit
      break;
  }
}

Otherwise the only possibility to stop your process is by sending a SIGKILL signal - you can do this on the shell by typing "kill -9 PID" (where -9 is the numerical value for SIGKILL).

Note: You cannot add a handler (i.e. ignore signals) for SIGSTOP and SIGKILL - for obvious reasons.
up
down
-1
jjoss
3 years ago
By default pcntl library is not enabled on web server installation. In order to use pcntl_fork() function you need to compile and enable pcntl.so module. That is pretty easy on Ubuntu.

Login as superuser

Firstly install the php5-dev package:

  apt-get install php5-dev

Create a temporary folder and get php sources

  mkdir php
  cd php
  apt-get source php5

Then go into the extension directory. 

  cd php5-5.1.2/ext/pcntl

Compile the extension

  phpize
  ./configure
  make

Copy the extension

  cp modules/* /usr/lib/php5/20051025/

Your php5 library directory might be named something else.
Restart Apache

  apache2 -k restart

原创粉丝点击