欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 八卦 > Linux——信号

Linux——信号

2025/4/19 1:22:27 来源:https://blog.csdn.net/m0_74774362/article/details/147116994  浏览:    关键词:Linux——信号

目录

一、信号的概念

二、信号的处理

三、信号的发送

四、通过信号处理僵死进程 


一、信号的概念

在Linux系统中,信号是一种进程间通信的机制,用于通知进程发生了某个事件。信号可以由内核、其他进程或进程自身发送。信号的本质就是用软件来模拟中断的行为。例如,当用户按下Ctrl+C键发送中断信号给一个运行中的进程时,该进程会收到SIGINT信号,通常会导致进程终止。

Linux系统提供了多种信号,每个信号都用一个唯一的整数值标识。有一些常见的信号,比如SIGINT(中断)、SIGKILL(强制终止)、SIGTERM(正常终止)、SIGCHLD(子进程状态改变)等。通过发送不同的信号,可以实现进程的控制、通知和同步。

二、信号的处理

在Linux中,进程可以通过系统调用signal()sigaction()来注册信号处理函数,以处理接收到的信号。处理函数可以是系统提供的默认处理方式,也可以是自定义的处理方式。通过信号的机制,可以实现进程之间的通信、协作和错误处理等功能。

进程可以对信号进行以下几种处理:
默认处理:系统为每种信号定义了默认行为。例如,SIGINT 的默认行为是终止进程。
忽略信号:进程可以选择忽略某些信号(除了 SIGKILL 和 SIGSTOP)。收到信号但不执行
捕获信号:进程可以通过信号处理函数捕获并处理信号。用户捕捉某个或某些信号,并对它们的功能进行修改

信号处理函数是一个用户自定义的函数,当进程接收到信号时,会调用该函数。可以通过 signal 或 sigaction 系统调用来设置信号处理函数。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>void fun(int sig)
{printf("sig=%d\n",sig);//2
}int main()
{signal(SIGINT,fun);//设置信号的响应方式,达成约定,如果接收到信号,就调用fun函数while(1){printf("hello pid=%d\n",getpid());sleep(1);}
}

运行结果: 

运行程序会无限循环打印"hello的pid号",按Ctrl+C时,程序不会终止,而是会捕获SIGINT信号,并调用fun函数打印出信号的编号。只有按Ctrl+\ 时才会终止程序。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>void fun(int sig)
{printf("sig=%d\n",sig);//2signal(sig,SIG_DFL);
}int main()
{signal(SIGINT,fun);//设置信号的响应方式while(1){printf("hello pid=%d\n",getpid());sleep(1);}
}

运行结果:

和上次不同的是调用fun函数后会执行默认的代码,然后接收到默认的信号,按Ctrl+C会打印出信号的编号,在下一次执行的时候按Ctrl+C就会结束程序。

三、信号的发送

使用kill命令,他需要的头文件和函数形式如下:

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);

kill函数的两个参数中,第一个参数pid代表的是给哪个进程发送,这个进程的pid号;第二个参数是信号的代号。发送成功与否我们要看它的返回值,如果返回值是-1,那么就发送失败了。

第一种方式:atoi

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>//argc 参数个数  
//argv 参数内容
int main(int argc,char* argv[])
{if(argc!=3){printf("argc err\n");exit(1);}int pid=atoi(argv[1]);int sig=atoi(argv[2]);if(kill(pid,sig)==-1){printf("kill err\n");exit(1);}exit(0);//printf("argc=%d\n",argc);//for(int i=0;i<argc;i++)//{//  printf("argv[%d]=%s\n",i,argv[i]);//}
}

运行结果: 

第二种方式:sscanf

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>//argc 参数个数  
//argv 参数内容
int main(int argc,char* argv[])
{if(argc!=3){printf("argc err\n");exit(1);}int pid=0;int sig=0;sscanf(argv[1],"%d",&pid);sscanf(argv[2],"%d",&sig);if(kill(pid,sig)==-1){printf("kill err\n");exit(1);}exit(0);
}

运行结果:

四、通过信号处理僵死进程 

通过以下代码可以看出子进程先结束,父进程没有获取子进程的退出码,使进程变成僵死进程。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>
#include<sys/wait.h>void fun(int sig)
{printf("sig=%d\n",sig);
}
int main()
{int n=0;char*s=NULL;signal(SIGCHLD,fun);pid_t pid=fork();if(pid==-1){exit(1);}if(pid==0){n=2;s="child";}else{n=7;s="parent";}for(int i=0;i<n;i++){printf("s=%s\n",s);sleep(1);}exit(0);
}

运行结果:

那么我们就可以利用信号处理僵死进程:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>// 信号处理函数,用于打印接收到的信号编号,并等待子进程结束
void fun(int sig)
{wait(NULL);printf("sig=%d\n",sig);
}int main()
{int n = 0;char* s = NULL;signal(SIGCHLD,fun); // 注册信号处理函数fun,用于处理SIGCHLD信号pid_t pid = fork();if (pid == -1) {exit(1); }if (pid == 0) {n = 3;s = "child";}else{n = 7;s = "parent";}// 根据进程类型打印相应次数的标识字符串for(int i = 0; i < n; i++){printf("%s\n",s);sleep(1); }exit(0); 
}

运行结果:

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com