发送信号的几种形式

  1. kill -s 信号编号|信号名字 进程PID
  2. 在程序中使用posix_kill 给一个指定的进程或是进程组发送信号
  3. pcntl_alarm SIGALRM
  4. 在终端按下特殊键 ctrl+c、 ctrl+z、ctrl+\
  5. 网络 SIGURG、SIGPIPE、SIGCHLD(当子进程结束的时候)

pcntl_signal_dispatch

pcntl_signal_dispatch,调用等待信号的处理器。

调用每个等待信号通过 pcntl_signal 安装的处理器。

posix_kill

posix_kill,Send a signal to a process.

Send the signal to the process with the process identifier process_id.

kill, send signal to a process.

The kill() system call can be used to send any signal to any process group or process.

If pid is positive, then signal sig is sent to the process with the ID specified by pid.

If pid equals 0, then sig is sent to every process in the process group of the calling process.

If pid equals -1, then sig is sent to every process for which the calling process has permission to send signals, except for process 1 (init), but see below.

If pid is less than -1, then sig is sent to every process in the process group whose ID is -pid.

If sig is 0, then no signal is sent, but existence and permission checks are still performed; this can be used to check for the existence of a process ID or process group ID that the caller is permitted to signal.

For a process to have permission to send a signal, it must either

be privileged (under Linux: have the CAP_KILL capability in the

user namespace of the target process), or the real or effective

user ID of the sending process must equal the real or saved set-

user-ID of the target process. In the case of SIGCONT, it

suffices when the sending and receiving processes belong to the

same session.

示例:


<?php

pcntl_signal(SIGINT, function($signo){

    fprintf(STDOUT, "pid %d 接收到 %d 信号\n", posix_getpid(), $signo);

});

pcntl_signal(SIGALRM,function($signo){

    fprintf(STDOUT,"pid %d 接收到 %d 信号\n",posix_getpid(),$signo);

});

// 创建的子进程都是兄弟进程,父进程ID,组ID都一样
$mapPid = [];
$pid = pcntl_fork();

if ($pid>0){

    $mapPid[] = $pid;

    $pid = pcntl_fork();
    if ($pid>0){

        $mapPid[] = $pid;

        while (1){

            pcntl_signal_dispatch();

            //1)pid>0
            //$pid 进程的标识PID
            //$sig 信号的编号|信号的名字
            posix_kill($mapPid[0],SIGINT);

            // 2)pid=0 就会向进程组中的每个进程发送信号
            // posix_kill(0, SIGINT);
            
            // 3) pid==-1 最好在自己的机器上
            // posix_kill(-1, SIGINT);

            sleep(2);
        }
        exit(0);
    }

}

// 这里是子进程的运行代码
while(1){

    pcntl_signal_dispatch();
    fprintf(STDOUT,"pid %d ppid=%d,pgid=%d doing...\n",posix_getpid(),posix_getppid(),posix_getpgrp());
    sleep(1);

}

pcntl_alarm

pcntl_alarm,创建一个计时器,在指定的秒数后向进程发送一个SIGALRM信号。每次对 pcntl_alarm() 的调用都会取消之前设置的alarm信号。

参数: seconds

等待的秒数。如果seconds设置为0,将不会创建alarm信号。

示例:


<?php

pcntl_signal(SIGALRM,function($signo){

    fprintf(STDOUT, "pid %d 接收到 %d 信号\n", posix_getpid(), $signo);

});

// 时间到之后,这个定时就会被 清理掉
pcntl_alarm(3);

while (1){
    pcntl_signal_dispatch();
    fprintf(STDOUT,"pid %d ppid=%d,pgid=%d doing...\n",posix_getpid(),
    posix_getppid(),posix_getpgrp());
    sleep(1);
}


$ php demo15.php
pid 1098 ppid=25,pgid=1098 doing...
pid 1098 ppid=25,pgid=1098 doing...
pid 1098 ppid=25,pgid=1098 doing...
pid 1098 接收到 14 信号
pid 1098 ppid=25,pgid=1098 doing...
pid 1098 ppid=25,pgid=1098 doing...
pid 1098 ppid=25,pgid=1098 doing...
pid 1098 ppid=25,pgid=1098 doing...
pid 1098 ppid=25,pgid=1098 doing...