Linux 信号(signal)的理解

对Linux来说,信号时软中断,许多重要的程序都需要处理信号。

信号为Linux提供了一种处理异步事件的方法。
比如:终端用户输入ctrl+c来中断程序,会通过信号机制停止一个程序。
信号概述:
1.信号的名字和编号
		每个信号都有一个名字和编号,这些名字都以"SIG"开头,例如"SIGIO","SIGCHLD"等
		等。
		信号定义在signal.h头文件中,信号名都定义为正整数。
		
		具体的信号名称可以使用kill -l来查看信号的名字以及序号,信号时从1开始编号的,
		不存在0号信号。kill对于信号0有特殊意义。
		
2.信号的处理
		信号的处理有三种方法:	忽略,捕捉和默认动作。
		
		忽略信号:大多数信号可以使用这个方式来处理,但是有两种信号不能被忽略(分别
		是SIGKILL和SIGSTOP)。因为他们向内核和超级用户提供了进程终止和停止的可靠方
		法。如果忽略,那么这个进程就变成了没人能管理的进程,显然是内核设计者不希望
		看到的场景。

		捕捉信号:需要告诉内核,用户希望如何处理某一种信号,说白了就是写一个信号处
		理函数,然后将这个函数告诉内核。当该信号产生时,由内核来调用用户自定义的函
		数,以此来实现某种信号的处理。

		系统默认动作:对于每个信号来说,系统都对应由默认的处理动作,当发生了该信号,
		系统会自动执行。不过,对系统来说,大部分的吃力方式都比较粗暴,就是直接杀死
		该进程。

	具体的信号默认动作可以使用 man 7 signal 来查看系统的具体定义。

3.信号处理函数的注册------入门版:signal			高级版:sigaction
	信号处理发送函数------入门版:kill				高级版:sigqueue
$:ps -aux|grep a.out-----------------查看a.out进程
$:kill -9 (进程ID) ------------------杀死进程
或$:kill -SIGKILL (进程ID)-----------杀死进程

对于信号而言,最大意义不是杀死信号,而是实现一些异步通讯手段。 
入门:			重在动作,没有携带信息
		signal原型:
				typedef	void(*sighandler_t)(int)---------函数指针

				sighandler_t signal(int signum,sighandler_t handler);
				int signum:信号编码
				sighandler_t(结构体) handler:函数指针
		kill原型:
				int kill(pid_t pid,int sig);
				pid:进程ID号
				sig:信号编号
例:按Ctrl+c不退出

#include <signal.h>
#include <stdio.h>

void handler(int signum)
{
        printf("get signum:%d\n",signum); // 打印信号的值

        printf("never quit\n");
}

int main()
{
        signal(SIGINT,handler);	//信号注册,捕捉信号
      //signal(SIGINT,SIG_IGN); //忽略信号,按Ctrl+c后没有反应,但仍可以用指令杀死

        while(1);

        return 0;
}

运行结果:	while(1):一直执行
					按Ctrl+c出现:
					^Cget signum:2
					never quit
					^Cget signum:2
					never quit
					^Cget signum:2
					never quit
					^Cget signum:2
					never quit
					^Cget signum:2
					never quit
				按Ctrl+x退出
				
通过软件编程来实现signal信号捕捉后对信号进行专配

信号处理dome

#include <signal.h>
#include <stdio.h>

void handler(int signum)
{
        printf("get signum:%d\n",signum);

        printf("never quit\n");
}

int main()
{
        signal(SIGINT,handler);

        while(1);

        return 0;
}


信号发送dome

#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <stdlib.h>

int main(int argc,char **argv)
{
        int signum;
        int pid;

        signum = atoi(argv[1]);		//因为是char **argv,所以要用atoi转成int
        pid = atoi(argv[2]);

        printf("signum:%d,pid:%d\n",signum,pid);

        kill(pid,signum);				//信号发送

        return 0;
}

也可以用shell脚本的方式去做:
		  char cmd[128] = {0};
		  sprintf(cmd,"kill -%d %d",signum,pid);
		  system(cmd); 来显示打印信息

运行结果:
	信号处理运行,信号发送要先得知信号处理的进程ID,通过(ps -aux|grep 运行程序名)
	查看。然后发送信号,杀死进程:./a.out 9 4325
高级:		发送信号的同时带有信息

接收信号原型:
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

struct sigaction {
   void       (*sa_handler)(int); //信号处理程序,不接受额外数据,SIG_IGN 为忽
   									略,SIG_DFL 为默认动作
   void       (*sa_sigaction)(int, siginfo_t *, void *); //信号处理程序,能够接受额
   															外数据和sigqueue配合使用
   sigset_t   sa_mask;//阻塞关键字的信号集,可以再调用捕捉函数之前,把信号添加到信
   						号阻塞字,信号捕捉函数返回之前恢复为原先的值。
   int        sa_flags;//影响信号的行为SA_SIGINFO表示能够接受数据
 };
//回调函数句柄sa_handler、sa_sigaction只能任选其一


信号发送函数:
#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);
union sigval {
   int   sival_int;
   void *sival_ptr;
 };

在这里插入图片描述

处理信号信息dome

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>


void handler(int signum, siginfo_t *info, void *context)
{
        printf("get signum:%d\n",signum);
        if(context != NULL){
                printf("get date:%d\n",info->si_int);
                printf("get date:%d\n",info->si_value.sival_int);
                printf("from:%d\n",info->si_pid);
        }
}

int main()
{
        struct sigaction act;
        printf("pid = %d\n",getpid());

        act.sa_sigaction = handler;
        act.sa_flags = SA_SIGINFO;

        sigaction(SIGUSR1,&act,NULL);
        while(1);

        return 0;
}
首先用sigaction来注册信号,注册的时候第一个参数是我要收哪一个信号,
第二个参数是我收到这个信号后想要干什么,第三个参数是用来备份。
第二个参数是这么回事,我要接收信号就必须指定里面的flags这个参数,收
到信号以后去调用handler来处理信号,handler收到信号后吧信号的值打印
出来(signum),接着把内容(info)打印出来,内容是否有,取决于context,
context非空的话,info就有内容,把info里面的si_int数据打印出来。



发送信号dome

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc,char **argv)
{
        int signum;
        int pid;

        signum = atoi(argv[1]);
        pid = atoi(argv[2]);

        union sigval value;
        value.sival_int = 999;

        sigqueue(pid,signum,value);-------value:联合体
        printf("done\n");

        return 0;
}


运行结果:

在这里插入图片描述

详细教程,在此网站:Linux 信号.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值