信号
信号是一种终端机制,程序运行到一半的时候接收到了某种通知,程序就会立刻中断运行,转而去处理通知。
登记信号
一个进程只会接收默认的几个信号
如果想要让一个进程接收特定信号的话,必须提前在该进程中登记一下想要接收的信号
typedef void (*sighandler_t)(int);
原型:sighandler_t signal(int signum, sighandler_t handler); .
调用:signal(1/2/3/.....,handler)
功能描述:
将signum信号,登记为当前进程所能捕获的信号。当进程捕获到 signum 信号之后,就会中断当前的运行,转而运行 handler函数
参数 signum:想要登记的信号的编号,使用 kill -l 查看
参数 handler:void(int)类型的函数指针,信号处理函数
handler除了传入一个函数指针之外,还有2个选项
SIG_IGN:该信号捕获到之后,忽略处理
SIG_DFL:该信号被捕获到之后,执行默认的操作
原型 void handler(int signum)
调用:signal(1/2/3/.....,handler)
功能描述:一旦进程捕获到一个被signal登记的信号之后,就会调用handler函数
参数 signum:当前被捕获到的
几个常用信号
SIGINT:当键盘键入 ctrl + c 时候发出
SIGTSTP:当键盘键入 ctrl + z 时候发出
SIGCHLD:当子进程死亡的时候,自动的向其父进程发出的信号
只能默认处理的信号:SIGKILL 和 SIGSTOP 无法自定义处理 或者 忽略处理
不能被忽略的信号:SIGSEGV段错误信号,但是段错误信号可以自定义处理
练习
父子进程同时捕获登记SIGINT信号
父进程:输出我是父进程
子进程:输出我是子进程
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;
pid_t pid;
void handler(int signum)
{
printf("%d\n",getpid());
if(signum == SIGINT)
{
if(pid>0)
{
printf("我是父进程\n");
exit(0);
}
else if(0==pid)
{
printf("我是子进程\n");
exit(0);
}
}
}
int main(int argc, const char *argv[])
{
pid_t pid=fork();
if(pid>0)
{
signal(SIGINT,handler);
printf("%d\n",getpid());
}
else
{
signal(SIGINT,handler);
printf("%d\n",getpid());
}
while(1);
return 0;
}
当一个子进程死亡的时候,会自动的向其父进程发出SIGCHLD信号 要求实现:当父进程接收
到子进程死亡信息的时候,回收子进程的资源,防止僵尸进程的出现
当一个子进程死亡的时候,会自动的向其父进程发出SIGCHLD信号 要求实现:当父进程接收
到子进程死亡信息的时候,回收子进程的资源,防止僵尸进程的出现
追加要求:父进程使用
循环创建500个子进程,每一个子进程创建完毕后,立刻死亡
要求测试,是否产生僵尸进程,
并做到没有僵尸进程
标准的不会产生僵尸进程的模型
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;
int i=0;
void handler(int signum)
{
while(1)
{
pid_t w=waitpid(-1,0,WNOHANG);
if(-1==w)
return;
}
printf("子进程的资源已被回收\n");
}
int main(int argc, const char *argv[])
{
for(int i=0;i<500;i++)
{
pid_t pid=fork();
if(pid>0)
{
printf("ppid=%d\n",getpid());
signal(SIGCHLD,handler);
//wait(0);
}
else
{
int p=getpid();
printf("pid=%d\n",p);
kill(getpid(),SIGKILL);
break;
}
}
while(1);
return 0;
}
4:有2个.c文件,每个.c文件都拥有一对父子进程,总共4个进程 A a B b 现在要求实现一个多
米诺骨牌的效果:
按ctrl+c结束a进程的运行,a进程结束运行之前,通过kill函数向b进程发送SIGINT信号,b进
程死亡后,B进程回收b进程的资源后,B进程再使用kill函数向A进程发送SIGTSTP信号后,大B进程结束运行。A进程接受到B进程的SIGTSTP信号后,会后a进程的资源后也结束运行
注意:kill函数要求获得另一个进程的pid,使用文件IO
这个题需要预习一个函数叫做 kill 函数
A.c文件
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;
void handle(int signum)
{
if(signum==SIGINT)
{
FILE* p=fopen("./b的pid","r");
pid_t b_pid;
fread(&b_pid,4,1,p);
kill(b_pid,SIGINT);
fclose(p);
printf("a死亡\n");
exit(0);
}
if(signum==SIGTSTP)
{
wait(0);
printf("A结束\n");
exit(0);
}
}
int main(int argc, const char *argv[])
{
pid_t pid=fork();
if(pid>0)
{
signal(SIGINT,SIG_IGN);
FILE* p1=fopen("./A的pid","w");
pid_t A_pid=getpid();
fwrite(&A_pid,4,1,p1);
fclose(p1);
signal(SIGTSTP,handle);
}
else
{
signal(SIGINT,handle);
}
while(1);
return 0;
}
B.c文件
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;
void handle(int signum)
{
if(signum==SIGINT)
{
sleep(1);
printf("b死亡\n");
exit(0);
}
if(signum==SIGCHLD)
{
sleep(1);
while(waitpid(-1,0,WNOHANG)!=-1);
FILE* p1=fopen("./A的pid","r");
pid_t A_pid;
fread(&A_pid,4,1,p1);
kill(A_pid,SIGTSTP);
fclose(p1);
printf("B死亡\n");
exit(0);
}
}
int main(int argc, const char *argv[])
{
pid_t pid=fork();
if(pid>0)
{
signal(SIGCHLD,handle);
}
else
{
FILE* p=fopen("./b的pid","w");
pid_t b_pid=getpid();
fwrite(&b_pid,4,1,p);
fclose(p);
signal(SIGINT,handle);
}
while(1);
return 0;
}