子进程何时终止,调用waitpid后要无休止的等待吗?
操作系统负责将子进程终止的消息告诉给父进程
信号处理机制:在特定事件发生时由操作系统向进程发送消息,为了响应该消息,执行与消息相关的自定义的操作。
信号与signal函数
信号注册函数
#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);
函数名: signal
参数: int signo, void(*func)(int)
返回类型: 参数为int,返回void型函数指针
子进程终止时调用child函数,child的参数为int,返回值为void
signal(SIGCHLD, child)
alarm函数
unsigned int alarm(unsigned int seconds);
返回0或者以秒为单位的距SIGALRM信号发生所剩时间
调用时传一个正整型参数,对应时间后产生 SIGALRM信号,若传0,则取消之前对SIGALRM信号的预约。如果预约后没有指定处理函数,则终止进程,不做任何处理
可以在 signal 函数中注册的信号
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void timeout(int sig) {
if (sig == SIGALRM) {
puts("time out");
}
alarm(2);
}
void keycontrol(int sig) {
if (sig == SIGINT) {
puts("ctrl+c pressed");
}
}
int main(int argc, char *argv[]) {
int i;
signal(SIGALRM, timeout);
signal(SIGINT, keycontrol);
alarm(2);
for (i = 0; i < 3; i++) {
puts("wait....");
sleep(100);
}
return 0;
}
结果:
很快就结束了,这是因为“发生信号时将唤醒由于调用 sleep 函数而进入睡眠状态的线程,并且线程一旦被唤醒,就不会再进入睡眠状态”。
sigaction 函数
int sigaction(int signo, const struct sigaction * act,
struct sigaction * oldact);
signo:与 signal 相同,传递信号信息
act:对应于第一个参数的信号处理函数信息
oldact:通过此参数获取之前注册的信号处理函数的指针,不需要则传 0
struct sigaction {
void (*sa_handler)(int); //保存信号处理函数的指针值
sigset_t sa_mask; //默认为 0
int sa_flags; //默认为 0
}
完整示例
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void timeout(int sig) {
if (sig == SIGALRM) {
puts("time out");
}
alarm(2);
}
int main(int argc, char *argv[]) {
struct sigaction act;
act.sa_handler = timeout;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM, &act, 0);
alarm(2);
for (int i = 0; i < 3; i++) {
puts("wait....");
sleep(100);
}
return 0;
}
利用信号处理技术消灭僵尸进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
void read_childproc(int sig) {
int status;
pid_t id = waitpid(-1, &status, WNOHANG);
if (WIFEXITED(status)) {
printf("remove proc id: %d \n", id);
printf("child send: %d \n", WEXITSTATUS(status));
}
}
int main(int argv, char *argc[]) {
pid_t pid;
struct sigaction act;
act.sa_handler = read_childproc;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGCHLD, &act, 0);
pid = fork();
if (pid == 0) { //子进程
puts("hi, i'm child process1111");
sleep(10);
return 12;
} else { //父进程
printf("child proc id qqqqq: %d \n", pid);
pid = fork();
if (pid == 0) { //另一子进程
puts("hi i am child process2222");
sleep(10);
exit(24);
} else {
printf("child proc id xxxxxx: %d \n", pid);
for (int i = 0; i < 5; i++) {
puts("wait....");
sleep(5);
}
}
}
return 0;
}