1. 信号的本质
信号的本质就是整数,是用户模式下用来模拟硬件中断的一种方式。
硬件中断(真正中断):物理层面
软件中断(模拟中断):模拟
2. 信号的产生
- 硬件产生
- 内核产生
- 进程产生
3. 信号的处理过程
如果当前进程A正在运行,然后内核,硬件或者其它进程发送信号给进程A
进程A接收到信号之后:
1. 直接做信号本身规定的对应处理(例如SIGINT就是关闭进程(ctrl + C))
2. 做事先注册好的信号处理(信号注册函数signal(信号,处理函数))
3. 信号被屏蔽,等待信号屏蔽解除然后做出相应处理
4. 信号的分类
4.1 Linux提供的64个信号
kill -l
4.2 按照可靠性分类
不可靠信号:非实时性的信号 由UNIX提供的 1 --- 31
可靠信号:实时性的信号 后来扩充的 32 --- 64
4.3 按照类型分
标准信号:操作系统提供的信号
自定义信号:用户自定义的信号 SIG_USR
5. 信号注册与信号发送
5.1 信号注册
5.1.1 signal函数
不含signal 函数的一个进程, 使用Ctrl + C 或者 Ctrl + \ 可以结束当前进程
标准信号处理函数
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum,sighandler_t handler);
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
int main(){
printf("pid: %d\n",getpid());
int n = 0;
while(1){
printf(">> %d\n",n++);
sleep(1);
}
return 0;
}
使用signal函数注册SIGINT信号后, 当注册SIGINT信号之后, 使用Ctrl + C 发送SIGINT信号就会调用自定义的信号处理函数
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
//SIGINT信号处理函数
void hand(int val){
printf("val---%d\t想干掉我,没门!\n",val); //val 为 signum SIGINT的值为2
}
int main(){
signal(SIGINT,hand); //注册信号处理(信号自己处理,不交给操作系统处理)
printf("pid: %d\n",getpid());
int n = 0;
while(1){
printf(">> %d\n",n++);
sleep(1);
}
return 0;
}
5.1.2 sigaction函数(高级信号注册函数)
sigaction()高级信号注册函数对应sigqueue()高级信号发送函数
int sigaction(int signum, const struct sigaction* act, struct sigaction* oldact)
参数一: 信号的id(例如SIGINT信号的signum 为 2)
参数二: 新的信号处理方式
参数三: 旧的信号处理方式
struct sigaction{
void (*sa_handler)(int); //原来的信号处理函数
void (*sa_sigaction)(int, siginfo_t *,void *); //高级的信号处理函数
sigset_t sa_mask; //信号屏蔽
int sa_flags; //使用原来的还是高级的信号处理函数
void (*sa_restorer)(void); //目前未使用
};
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
void hand(int n){
printf("基本的信号处理函数!\n");
}
//参数1 信号 参数2 信号的一些信息(信号发送者给传入的数据) 参数3 注册信号传入的参数
void handler(int n,siginfo_t* siginfo,void* arg){
printf("高级的信号处理函数!\n");
printf("n:%d,msg:%d\n",n,siginfo->si_int);
}
int main(){
printf("pid--->%d\n",getpid());
struct sigaction act = {0};
struct sigaction oldAct = {0};
act.sa_handler = hand; //信号处理函数
act.sa_sigaction = handler; //高级信号处理函数
//sa_mask //信号屏蔽
//*sa_restorer //目前未使用
act.sa_flags = SA_SIGINFO; //sigaction替换handler
//SIGINT
sigaction(2,&act,&oldAct); //注册高级信号处理
//参数三作为返回值存在的
int n = 0;
while(1){
printf(">>> %d\n",n++);
sleep(1);
}
return 0;
}
5.2 信号发送
5.2.1 kill函数
kill(pid,sid); 参数1: 进程id 参数二: 信号
#include <stdio.h>
#include <unistd.h>
//信号的发送之kill函数
int aton(char* str){
int num = 0;
while(*str){
num = num * 10 + (*str-'0');
str++;
}
return num;
}
int main(int argc,char* argv[]){
int pid = aton(argv[1]); //进程id
int sid = aton(argv[2]); //信号id 2(SIGINT信号)
printf("%d %d",pid,sid);
// 进程id 信号id
kill(pid,sid);
return 0;
}
5.2.2 sigqueue函数(高级信号发送函数)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
int aton(char* str){
int num = 0;
while(*str){
num = num * 10 + (*str-'0');
str++;
}
return num;
}
int main(int argc,char* argv[]){
int pid = aton(argv[1]);
int sid = aton(argv[2]);
union sigval u;
u.sival_int = 6666666;
sigqueue(pid,sid,u);
return 0;
}
5.2.3 kill命令
kill sid -s pid
sid: 信号id pid: 进程id
6. 信号屏蔽
**int sigprocmask(int how, const sigset\_t\* set, sigset\_t\* oldset);**
**参数一: 是否屏蔽(或者其它的操作) SIG\_BLOCK(屏蔽) SIG\_UNBLOCK(不屏蔽)**
**参数二: 指向信号集的指针,新设的信号集**
**参数三: 指向信号集的指针,原来的信号集**
**返回值: 成功返回 0**
**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); //判断某个信号是否在信号集中**
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
void hand(int n){
printf("基本的信号处理函数!\n");
}
int main(){
printf("pid: %d\n",getpid());
sigset_t set,oldSet;
sigemptyset(&set); //清空信号集
sigaddset(&set,2);
//5秒钟不设置信号屏蔽
signal(2,hand);
sleep(5);
//设置信号屏蔽20秒
//sigismember 判断信号是否在信号集中
int ret;
if(1 == sigismember(&set,2)){
printf("设置信号屏蔽!\n");
ret = sigprocmask(SIG_BLOCK,&set,&oldSet);
//参数1 屏蔽还是解除屏蔽
//参数3为返回值 返回old信号集
if(0 == ret)
printf("设置信号屏蔽成功!\n");
else
printf("设置信号屏蔽失败!\n");
}
sleep(20);
//解除信号屏蔽
if(1 == sigismember(&set,2)){
printf("解除信号屏蔽!\n");
ret = sigprocmask(SIG_UNBLOCK,&set,&oldSet);
if(0 == ret)
printf("解除信号屏蔽成功!\n");
else
printf("解除信号屏蔽失败!\n");
}
while(1);
return 0;
}