信号 发信号 进程接收信号后响应信号

信号

信号的概念

信号是系统响应某个条件而产生的事件,进程接收到信号会执行相应的操作。
与信号有关的系统调用在“signal.h”头文件中有声明

响应信号
在键盘上按下 Ctrl+c 时,会给当前终端前台执行的进程发送 SIGINT 信号:

正常Ctrl+c 终止执行

  #include<stdio.h>
  #include<stdlib.h>
  #include<unistd.h>
  #include<string.h>
  #include<assert.h>
  #include<signal.h>
  
  int main(){
      while(1){
          printf("hello\n");
          sleep(1);
      }
      exit(0);  
  }

在这里插入图片描述

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
参数含义:signum 代表信号的值;handler 是一个函数指针此处调用函数
忽略:SIG_IGN
默认:SIG_DEF
自定义:自己编写的信号函数

用 signal 修改 SIGINT 信号的响应方式示例代码如下:

 #include<stdio.h>
 #include<stdlib.h>
 #include<unistd.h>
 #include<string.h>
 #include<assert.h>
 #include<signal.h>
 void sig_fun(int sig){
 
     printf("sig=%d\n",sig);
 
 }
 int main(){
 
     signal(SIGINT,sig_fun);//收到SIGINT信号才会执行
 
     while(1){
         printf("hello\n");
         sleep(1);
     }
 
 }

在这里插入图片描述
此时可以看出Ctrl+c 并不能像之前一样结束程序执行.
使用signal之后,按下Ctrl+c会收到SIGINT的信号,直接会产生软中断,按照signal函数第二个参数确定此时执行的方式(此处是自定义方式),去执行signal中函数指针参数所指向的函数(此函数参数为信号的值).执行完signal()之后恢复程序执行.

修改程序使得第一次接收到SIGINT信号后打印信号值第二次接收到SIGINT信号后正常终止.

 void sig_fun(int sig){
 
     printf("sig=%d\n",sig);
     signal(SIGINT,SIG_DFL);//此时重新设置了响应方式
 
 }

在这里插入图片描述

发送信号

kill() 可以向指定的进程发送指定的信号:
int kill(pid_t pid, int sig);
pid > 0 指定将信号发送个那个进程
pid == 0 信号被发送到和当前进程在同一个进程组的进程
pid == -1 将信号发送给系统上有权限发送的所有的进程
pid < -1 将信号发送给进程组 id 等于 pid 绝对值,并且有权限发送的所有的进程。
sig 指定发送信号的类型。

向进程发送信号(与上面结合)

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<signal.h>
//./mykill  pid   sig
 int main(int argc,char *argv[]){

     if(argc!=3){//argv[1]存放pid argv[2]存放sig
         printf("mykill arg err\n");
         exit(0);
      }
 
      int pid=0;
      int sig=0;
      sscanf(argv[1],"%d",&pid);//字符串转整型
      sscanf(argv[2],"%d",&sig);
       //给进程号==pid的进程发送sig信号
      if(kill(pid,sig)==-1){
          printf("kill err\n");
      }
      exit(0);
 
 }

在这里插入图片描述
第一次发送信号 打印信号值 第二次发送信号终止

kill -9 pid

9号信号的响应方式不允许改变(不允许使用signal改变响应方式,改变不会成功,只能以默认方式响应).

SIGCHLD 17 子进程结束后,父进程会收到该信号.

代码演示

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<signal.h>
#include<sys/wait.h>
void sig_fun1(int sig){

     printf("sig=%d ",sig);
     wait(NULL);//此时不会阻塞父进程
     //只有在子进程执行完成后才会发出信号执行自定义函数,获取子进程退出码
 }
 int main(){
 
     int n=0;
     char *s=NULL;
     signal(SIGCHLD,sig_fun1);
     pid_t pid= fork();
     assert(pid!=-1);
 
     if(pid==0){
         s="child";
         n=3;
     }
     else{
         s="parent";
         n=7;
     }
     for(int i=0;i<n;++i){
         printf("s=%s\n",s);
         sleep(1);
     }
     exit(0);

 }

在这里插入图片描述
子进程结束后发出信号,父进程捕获到信号,响应信号转到此处自定义函数执行,打印信号的值.

signal(SIGCHLD,SIG_IGN)Linux特有 unix不能, 设置成忽略,和内核达成约定不关注子进程,子进程结束完该释放释放,不用保留退出码,不关心.

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值