信号

2020-08-26 10:48:21 浏览数 (1)

7.1 信号的概念

什么是信号:

信号是UNIX系统响应某些状况而产生的事件,进程在接收到信号时会采取相应的行动。

信号的特点:

简单,不能携带大量信息,满足特定条件才会发生。信号也叫软中断,有可能会有延迟。

信号的实现机制:

信号实际上是由内核发送,内核来处理收到的信号。收到信号的进程,必须对信号做出处理(忽略,捕获,默认动作都行)

信号的产生:

信号状态:

产生 递达:信号被捕捉并处理 未决:信号被阻塞

信号四要素:

编号、事件、名称、默认处理动作

7.2 进程处理信号行为
代码语言:javascript复制
1、默认动作
2、忽略
3、捕捉
(后面两种处理行为就需要涉及到信号集了)
7.3 信号集处理函数

(1)首先要了解什么是信号集:

代码语言:javascript复制
信号集被定义为一种数据类型:

typedef struct {

                       unsigned long sig[_NSIG_WORDS];

} sigset_t

//信号集用来描述信号的集合,每个信号占用一位(64位)。
//Linux所支持的所有信号可以全部或部分的出现在信号集中,主要与信号阻塞相关函数配合使用。

//下面是为信号集操作定义的相关函数:

#include <signal.h>

int sigemptyset(sigset_t *set);

int sigfillset(sigset_t *set);

int sigaddset(sigset_t *set, int signum);

int sigdelset(sigset_t *set, int signum);

int sigismember(const sigset_t *set, int signum);

(2)信号集处理函数:

那我们一个一个来看

int sigemptyset(sigset_t *set); //清空信号集嘛,传参传什么也应该很清楚了 初始化由set指定的信号集,信号集里面的所有信号被清空,相当于64为置0;

int sigfillset(sigset_t *set);//填满信号集嘛 调用该函数后,set指向的信号集中将包含linux支持的64种信号,相当于64为都置1;

int sigaddset(sigset_t *set, int signum);//添加信号进去 在set指向的信号集中加入signum信号,相当于将给定信号所对应的位置1;

int sigdelset(sigset_t *set, int signum);//删除信号出去 在set指向的信号集中删除signum信号,相当于将给定信号所对应的位置0;

int sigismember(const sigset_t *set, int signum);//看看是不是已经在里面了 判定信号signum是否在set指向的信号集中,相当于检查给定信号所对应的位是0还是1。

好,看完上面这些处理函数,其实这几个函数真的就是对信号集进行操作而已,而不会对具体信号有什么动作。 别急

7.4 阻塞信号集

阻塞信号集也叫做当前进程的信号屏蔽字。 这里的屏蔽应该理解为阻塞而非忽略

(1)sigprocmask 调用sigprocmask函数可以读取或更改进程的信号屏蔽字。

代码语言:javascript复制
#include<signal.h>

int sigprocmask(int how,const sigset_t *set,sigset_t *oldset);
//成功返回0,失败返回-1

参数释义: set:用于更改的信号集 oldset:用于传出原信号集 how:怎么操作set

how的参数选择: SIG_BLOCK:set包含了我们希望添加到当前信号屏蔽字的信号 SIG_UNBLOCK:set包含了我们希望从当前信号屏蔽字移除的信号 SIG_SETMASK:设置当前信号屏蔽字为set所指向的值。

这个要生效的话,至少需要有其中一个信号的驱动(就是哪个倒霉的过来阻塞一下)

(2)sigpending

代码语言:javascript复制
#include<signal.h>

int sigpending(sigset_t *set);

//成功返回0,失败返回-1

功能:读取当前进程的未决信号集,通过set参数传出。

到这里差不多可以去弄信号集了

7.5 信号捕捉设定
防止信号意外死亡
代码语言:javascript复制
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

参数释义 signum 捕捉的信号 act 传入的动作 oldact 原动作

我去借鉴了一段代码:捕捉我们给自己定时发送的14号自杀信号:

代码语言:javascript复制
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<sys/time.h>
 
//定义捕捉函数
void catch_sig(int num){
	printf("catch %d sign", num);
}
 
int main(){
	//注册捕捉函数
	struct sigaction act;
	//说明为你使用的是sigaction结构体中的第一个捕捉函数
	act.sa_flags=0;
	//那个捕捉函数的函数指针指向我们上面自己写的捕捉函数catch_sig
	act.sa_handler=catch_sig;
	//清空信号集
	sigemptyset(&act.sa_mask);
	sigaction(SIGALRM, &act, NULL);
 
	//setitimer 5秒之后每隔3秒来一次信号
	struct itimerval myit={{3,0},{5,0}};  //这个后续章节会提到,我现在也不是很清楚
	setitimer(ITIMER_REAL, &myit, NULL);//还有这个
	while(1){
		printf("Who can kill me!n");
		sleep(1);
	}	
	return 0;
}
7.6 C标准库信号处理函数
代码语言:javascript复制
typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

//signum 要捕捉的信号
//handler 要执行的捕捉函数指针,函数应该声明 void func(int);//函数名可变
7.7 SIGCHLD 信号处理
17号信号

产生条件:

子进程结束时 子进程收到SIGSTOP信号时 子进程处在睡眠状态,收到SIGCONT信号唤醒时

哎,这个有点不好搞,我先把其他方法搞清楚咯 代码也是抄来的,贴这儿了

代码语言:javascript复制
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>
 
void catch_sig(int num){
	pid_t pid=waitpid(-1, NULL, WNOHANG);
	if(pid>0){
		printf("wait child %d okn", pid);
	}
}
 
int main(){
	int i=0;
	pid_t pid;
	for(i=0; i<10; i  ){
		pid=fork();
		if(pid==0){
			break;
		}
	}
	if(i==10){
		//father
		struct sigaction act;
		act.sa_flags=0;
		sigemptyset(&act.sa_mask);
		act.sa_handler=catch_sig;
		sigaction(SIGCHLD, &act, NULL);
		while(1){
			sleep(1);
		}
	}else if(i<10){
		printf("I am %d child, pid=%dn", i, getpid());
		sleep(i);
	}
	return 0;
}

0 人点赞