多进程05-信号处理

685 阅读1分钟

中断处理过程

信号 指软件终端信号,软中断

  1. 中断处理程序注册。进程注册中断处理程序。不能覆盖信号:sigkill,sigstop
  2. 中断源产生中断。按键、kill、定时器等
  3. 进程中断响应,忽略sig_ign,执行中断处理程序,执行系统默认处理程序sig_def
  4. 中断返回

中断处理程序实验:

function sigHandler($signo)
{
    printf("pid=%d, 接收到一个信号:%d\n", getmypid(), $signo);
}

// SIGKILL SIGSTOP 无法被捕捉,报错
// 设置信号捕捉
pcntl_signal(SIGINT,'sigHandler');
pcntl_signal(SIGUSR1,'sigHandler');


// 子进程继承父进程的中断程序,并且可以覆盖
$pid = pcntl_fork();
if ($pid == 0){
    pcntl_signal(SIGUSR1, function ($signo){
        printf("pid=%d, 覆盖的中断操作:%d\n", getmypid(), $signo);
    });
}

while (1){
    sleep(2);
    pcntl_signal_dispatch();
    printf(" %d work running.\n", getmypid());
}

//  kill -s SIGINT 16912
//  kill -s SIGUSR1 16912
//  kill 16912

信号集 pcntl_sigprocmask 设置或截取信号屏蔽字

pcntl_signal(SIGINT, function ($sigNo){
    printf("pid=%d, 接收到了信号:%d\n", getmypid(), $sigNo);
});

// 信号屏蔽字
$sigSet = [SIGINT, SIGUSR1];
pcntl_sigprocmask(SIG_BLOCK, $sigSet);

$i = 1;
while (1){
    sleep(2);
    pcntl_signal_dispatch();
    printf("pid=%d, work run\n", getmypid());

    if ($i == 5){
        printf("time come");
        pcntl_sigprocmask(SIG_UNBLOCK, $sigSet, $oldSet);
        print_r($oldSet);
    }
    $i++;
}

发送信号

  1. kill 命令 -s 信号编号 | 信号名称 进程PID
  2. 程序中的 posix_kill 给指定的进程组发送信号
  3. pcntl_alarm sigalrm
  4. 终端下特殊的按键
  5. 网络 SIGURG,SIGPIPE。子进程结束 SIGCHLD
// posix_kill
pcntl_signal(SIGINT, function ($sigNo){
    printf("pid %d 收到 %d 信号\n", posix_getpid(), $sigNo);
});

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

if ($pid > 0){
    $midPid[] = $pid;

    $pid = pcntl_fork();
    if ($pid > 0){
        $midPid[] = $pid;
        while (1){
//            foreach ($midPid as $i){
//                posix_kill($i, SIGINT);
//            }
            // 就会向进程组中的每个进程发送信号
            posix_kill(0, SIGINT);
            sleep(2);
        }
    }
}
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_signal(SIGALRM, function ($sigNo){
    printf("pid %d 收到 %d 信号\n", posix_getpid(), $sigNo);
});
pcntl_alarm(2);
while (1){
    pcntl_signal_dispatch();
    sleep(2);
}

// SIGCHLD
pcntl_signal(SIGCHLD, function ($sigNo){
    fprintf(STDOUT,"pid %d 接收到 %d 信号\n",posix_getpid(),$sigNo);

    $pid = pcntl_waitpid(-1,$status,WNOHANG);
    if ($pid>0){
        fprintf(STDOUT,"pid %d 退出了\n",$pid);
    }
});

$pid = pcntl_fork();
if ($pid>0){
    while (1){
        pcntl_signal_dispatch();
        sleep(2);
    }
}else{
    fprintf(STDOUT,"child pid %d 退出了\n",getmypid());
    exit(10);
}