目录
一、信号的特点
1)一个进程收到一个信号与处理器收到一个中断请求可以说是一样的(软中断)。
2)信号是异步的,一个进程不必通过任何操作来等待信号的到达。
3)信号是内核定义的,当相应的事件产生时,内核发射相应的信号。
二、信号的处理
进程可以通过3种方式来响应一个信号
1)忽略信号
即对信号不做任何处理,其中,有两个信号不能被忽略:SIGKLL和SIGSTOP。
接收到了,但是什么都不做。
2)捕捉信号
定义信号处理函数,当信号发生时,执行相应的处理函数。
3)默认操作
对每种信号都规定了默认操作,如 kill -l 查看到的命令
1) SIGHUP 终端关闭会发送 进程结束
2) SIGINT ctrl + c 终止当前进程 进程结束
3) SIGQUIT ctrl + \ 停止当前进程 进程结束
9) SIGKILL 杀死进程 进程结束
12) SIGUSR2 用户自定信号
14) SIGALRM 闹钟信号
19) SIGSTOP 进程暂停
20) SIGTSTP ctrl+z 挂起进程 转换成后台进程
三、信号的发送
信号发送函数:kill()、raise();
(1)函数:kill 发送信号
函数原型:int kill(pid_t pid, int sig);
头文件:#include <signal.h> #include <sys/types.h>
参 数: pid 需要发送哪个进程的id, sig 是需要发送的信号
> 0 发送sig信号给pid的进程(一个进程)
0 发送给正在调用的进程组所在进程下的所有id
-1 发送sig信号给所有进程(除了1号init进程)
<-1 给进程组为绝对值pid的组发送sig信号。
返回值:如果成功返回0 如果失败返回-1 错误信息存入errno
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
if(argc != 3)
{
printf("输入的格式错误<命令> <信号> <进程id>");
exit(-1);
}
int res = kill(atoi(argv[2]),-1 * atoi(argv[1]));
if(res < 0)
{
perror("kill");
exit(-2);
}
return 0;
}
(2)函数 raise 给自己发信号
函数原型: int raise(int sig);
头文件:#include <signal.h>
作 用: 给当前进程发送信号,相当于 kill(getpid(),sig)
参数: 需要放的信号内容
返回值: 如果成功返回 0,失败返回-1,错误信息errno
#include <stdio.h>
#include <signal.h>
#include <signal.h>
int main()
{
printf("hello!!!\n");
raise(9);
printf("world\n");
return 0;
}
四、设置信号函数:signal()
函数原型:sighandler_t signal(int signum, sighandler_t handler);
回调函数: typedef void (*sighandler_t)(int);
头文件: #include <signal.h>
参数: signum 信号的值,需要处理什么信号
handler 参数:
如果想忽略信号(SIG_IGN) 1
如果想默认操作(SIG_DEL)0
对信号自定义处理的回调函数地址
返回值:返回先前处理函数的指针,如果没有先前的处理函数则返回自己。如果失败返回SIG_ERR (-1)
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
/****信号处理函数******/
void add(int n)
{
printf("***加法****\n");
printf("add = %d\n", n + n);
}
void sub(int n)
{
printf("***减法****\n");
printf("add = %d\n", n - n);
}
void mul(int n)
{
printf("***乘法****\n");
printf("add = %d\n", n * n);
}
void div(int n)
{
printf("***除法****\n");
printf("add = %d\n", n / n);
}
/**********************/
int main()
{
signal(10,add);
signal(11,sub);
signal(12,mul);
signal(13,div);
while(1);
return 0;
}
五、其他函数:alarm(闹钟)、pause();
(1) alarm 闹钟信号 SIGALRM---14
函数原型:unsigned int alarm(unsigned int seconds); 【重】
头文件: #include <unistd.h>
作用:在参数seconds秒后发送一个闹钟给自己,信号名称:SIGALRM---14
返回值: 如果先前没有设置闹钟,成功返回0,失败返回-1
如果之前设置了闹钟,返回之前设置的闹钟剩余秒数,
注意: 一个进程只能有一个闹钟时间,如果在调用alarm()之前已经设置过闹钟时间,则任何以前的闹钟时间都被新值所替代。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int res = alarm(3);//设置闹钟信号,软中断
if(res < 0)
{
perror("res");
exit(-1);
}
while(1)
{
printf("我还活着\n");
sleep(1);
}
return 0;
}
(2)pause 堵塞当前进程
函数原型: int pause(void);
头文件:#include <unistd.h>
作用: 让当前进程处于堵塞状态,等待接受一个信号(终止信号或者引起调用信号处理函数的信号)
如果是非终止信号或者是不需要捕获的信号,则不会解除堵塞。
pause和wait的区别:
前者是等待另外的进程发送sigkill信号,而wait是父进程等待子进程的结束。
六、有名管道与信号结合
A,B两个进程相互通信,A发B收,B发A收,当A给B发消息时同时会发送一个信号,B接收到信号时会中断去读这个信息,同理当B给A发消息时同时会发送一个信号,A接收到信号时会中断去读这个信息。
A ---> 内核--->发信号--->B
B ---> 内核--->发信号--->A
B进程跟A进程相似,A如下图,B省略
A进程
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
int fd0, fd1;
void read_r(int n);
char buf0[128] = {0};
char buf1[128] = {0};
int main()
{
if (access("./aname", F_OK) == -1) //检测是否存在,如果不存在则创建
{
int res = mkfifo("./aname", 0666);
if (res < 0)
{
perror("mkfifo");
exit(-1);
}
}
if (access("./bname", F_OK) == -1) //检测是否存在,如果不存在则创建
{
int res = mkfifo("./bname", 0666);
if (res < 0)
{
perror("mkfifo");
exit(-1);
}
}
fd0 = open("./aname", O_RDWR);
fd1 = open("./bname", O_RDWR);
int pid1 = 0;
int pid = getpid();
write(fd1, &pid, sizeof(pid));
read(fd0, &pid1, sizeof(pid1));
signal(10, read_r); //读
while (1)
{
memset(buf1, 0, sizeof(buf1));
scanf("%s", buf1);
write(fd1, buf1, sizeof(buf1));
kill(pid1, 12);
if (strcmp(buf1, "quit") == 0)
{
kill(pid1, 9);
break;
}
}
}
void read_r(int fd)
{
read(fd0, buf0, sizeof(buf0));
printf("B: %s\n", buf0);
}
B进程
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
int fd0, fd1;
char buf0[128] = {0};
char buf1[128] = {0};
void write_w(int n);
int main()
{
if (access("./aname", F_OK) == -1) //检测是否存在,如果不存在则创建
{
int res = mkfifo("./aname", 0666);
if (res < 0)
{
perror("mkfifo");
exit(-1);
}
}
if (access("./bname", F_OK) == -1) //检测是否存在,如果不存在则创建
{
int res = mkfifo("./bname", 0666);
if (res < 0)
{
perror("mkfifo");
exit(-1);
}
}
fd0 = open("./aname", O_RDWR);
fd1 = open("./bname", O_RDWR);
int pid = 0;
int pid1 = getpid();
read(fd1, &pid, sizeof(pid));
printf("%d\n", pid);
write(fd0, &pid1, sizeof(pid1));
signal(12, write_w);
while (1)
{
memset(buf0, 0, sizeof(buf0));
scanf("%s", buf0);
write(fd0, buf0, sizeof(buf0));
kill(pid, 10);
if (strcmp(buf0, "quit") == 0)
{
kill(pid, 9);
break;
}
}
return 0;
}
void write_w(int n)
{
read(fd1, buf1, sizeof(buf1));
printf("A: %s\n", buf1);
}