1. 信号通信
1) 信号是一种异步通信方式,是软件层次上对中断机制的一种模拟。
2) 信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。
3) 如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复再执行再传递给它;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。
2. 用户进程对信号的相应方式
忽略信号:对信号不做任何处理,但是有两个信号不能忽略:即SIGKILL及SIGSTOP。
捕捉信号:定义信号处理函数,当信号发生时,执行相应的处理函数。
执行缺省操作: Linux对每种信号都规定了默认操作。
3. 使用信号的场合
1)后台进程需要使用信号,如xinetd(管理网络服务)。
2)如果两个进程没有亲缘关系,无法使用无名管道
3)如果两个通信进程之一只能使用标准输入和标准输出,则无法使用FIFO
4. 常见的信号与缺省动作
5. 信号发送与捕捉函数kill()和raise()
1)信号发送
函数kill()
头文件:#include<sys/types.h>
#include<signal.h>
函数原型:int kill(pid_t pid, int sig)
函数参数:
pid:
正数 发送信号给进程标识符为pid的进程
0 信号被发送到所有和当前进程在同一个进程组的进程
-1 信号被发送给所有的有权给其发送信号的进程(除了1号init进程)
<-1 信号发送给进程组号为-pid的每个进程
sig 需要发送的信号。若为0则不会送出信号,但是系统会执行错误检查。通常用0来检测某个进程是否正在运行
函数返回值:
成功:0
失败:-1
2)信号发送
函数raise()(注:该函数允许进程向自己发送信号,等价于kill(getpid(),sig)或pthread_kill(pthread_self(),sig))
头文件:#include<signal.h>
函数原型:int raise(int sig)
函数参数:
sig 需要发送的信号。若为0则不会送出信号,但是系统会执行错误检查。通常使用0来检测某个进程是否正在运行
函数返回值:
成功:0
失败:-1
示例代码:
/*************************************************************************
@Author: wanghao
@Created Time : Wed 23 May 2018 08:31:31 PMPDT
@File Name: signal.c
@Description:
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
int main(int argc, const char *argv[])
{
pid_tpid;
if((pid= fork()) < 0)
{
perror("");
exit(1);
}
if(pid== 0)
{
//raise(SIGSTOP);
printf("childprocess exit...\n");
exit(0);
}
else
{
printf("pid= %d\n",pid);
sleep(1);
if(waitpid(pid,NULL, WNOHANG))
{
kill(pid,SIGKILL);
printf("kill= %d\n",pid);
}
}
return0;
}
运行结果:
pid = 3417
child process exit...
kill = 3417
6. 信号发送与捕捉函数alarm()与pause()
alarm()函数也称为闹钟函数,它可以在进程中设定一个定时器,当定时器计时结束时,它就会向进程发送SIGALRM信号,并且在终端输出"Alarm clock"表示计时结束。
pause()函数用于将该进程挂起直至接收到某个信号为止。
1) 函数alarm()
头文件:#include<unistd.h>
函数原型:unsigned int alarm(unsigned intsecond)
函数参数:
second 指定倒计时秒数,在second秒后发送SIGALRM信号
函数返回值:
成功:如果在调用alarm前已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间(注意是上一个闹钟时间不是本次alarm),如果以前没有设置国闹钟返回0.
失败:-1
2) 函数pause()
头文件:#include<unistd.h>
函数原型:int pause()
函数参数:无
函数返回值:-1,并且把errno设定为EINTR(仅会在接收到信号后返回)
示例:调用alarm()函数设置闹钟,pause()函数暂停本进程,直到本进程收到闹钟信号,
唤醒本进程。
示例代码:
/*************************************************************************
@Author: wanghao
@Created Time : Wed 23 May 2018 10:49:24 PMPDT
@File Name: alarm.c
@Description:
************************************************************************/
#include <stdio.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
intret;
ret= alarm(5);
pause();
printf("Ihave been waken up.\n");
return0;
}
7. 信号的处理
1)特定的信号是与相应的事件相联系的。
2)一个进程可以设定对信号的相应方式。
3)信号处理的主要方法有两种
使用简单的signal()函数
使用信号集函数族
4)使用signal()函数处理时,需指定要处理的信号和处理函数
8.信号处理函数
函数signal()
头文件:#include<signal.h>
函数原型:
typedefvoid (*sighandler_t)(int);
sighandler_tsignal(int signum, sighandler_t handler);
函数参数:
signum 指定信号
handler 指定接收信号后的处理方式
SIG_IGN:忽略信号
SIG_DFL:采用默认方式处理信号
其他:自定义信号处理函数
函数返回值:
成功:以前的信号处理函数
失败:SIG_ERR
示例: 将信号SIGINT和SIGQUIT的默认操作改为自定义操作。(注: 不能更改SIGKILL及SIGSTOP默认操作)
示例代码:
/*************************************************************************
@Author: wanghao
@Created Time : Wed 23 May 2018 11:12:56 PMPDT
@File Name: signal_handle.c
@Description:
************************************************************************/
#include <stdio.h>
#include <signal.h>
void my_func(int sign_no);
int main(int argc, const char *argv[])
{
printf("Changesignal SIGINT and SIGQUIT function!\n");
signal(SIGINT,my_func);
signal(SIGQUIT,my_func);
while(1)
{
sleep(1);
}
return0;
}
void my_func(int sign_no)
{
if(sign_no== SIGINT)
{
printf("Igot SIGINT\n");
}
elseif(sign_no == SIGQUIT)
{
printf("Igot SIGQUIT\n");
}
}
运行该程序,在另一个窗口输入:
kill -2 3664
kill -3 3664
kill -9 3664
结果如下:
Change signal SIGINT and SIGQUIT function!
I got SIGINT
I got SIGQUIT
Killed