进程通信之信号

/********************************************************************
2014/7/16 9:19:58 王斌
\********************************************************************
进程间通信技术1--------信号
一、认识信号【*】
1.信号基本知识
--进程间通信原理
PID
--怎么通过命令发送信号?
kill -2 PID (2是中断信号的编号)
--我们能够发送什么信号?
kill -l (前32个信号)--列出所有信号
man 7 signal --信号的默认属性
--怎么使用ps命令
ps -l (列出当前终端的进程)
ps l (列出所有终端的进程)
--ctrl+c的本质?
只能结束当前终端的前台进程 --kill -3 PID
--信号是异步事件
同步时间就是在确定时间发生(比如在20秒后绿灯变成红灯)
异步事件就是在任何时候都可能发生的事件(可以在任意时间发送信号)
软件中断:模式和硬件中断相同
--信号都有默认方式,是否可以修改默认方式。
默认方式:中断,停止,忽略(子进程死亡的时候,会给父进程发送一个忽略信号)

2.信号的认识
(1)信号是软件模拟的中断
(2)信号提供了一种处理异步事件的方法.
(3)产生信号的事件对进程而言是随机的.

3.信号:系统预先定义的一些固有的消息,并且定义了对应的缺省处理方式.
每个信号都有一个名字,这些名字都以三个字符SIG开头;
在头文件SIGNAL.H中
4.如何查看信号:kill -l(关注的是1-34)
5.如何产生信号:通过终端按键
ctrl^c --SIGINT
ctrl^\--SIGQUIT
ctrl^z--SIGSTSP
通过shell指令
kill -n pid 向pid进程发送n号信号
kill pid 向pid发送15号信号(SIGTERM)信号
kill -9 pid 9号信号
一些函数:
abort ---SIGABRT
alarm ---SIGALRM
exit ---SIGCHLD
系统调用:
kill(2)
raise(3)
其他情况:
读写端关闭管道 产生SIGPIPE
除0运算 产生SIGRPE
访问非法内存产生SIGSEGV
6.信号的处理方式
(1)忽略
(2)捕捉
(3)执行系统默认指令

7.信号的分类:
可靠信号,不可靠信号

实时信号,非实时信号
8.信号的处理流程:(以CTRL^C为例)
信号在处理前被记录在进程的pcb中
当进程从内核态返回到用户态时,会首先检查PCB中是否有需要处理的信号,如果有就处理
二.产生信号【*】
man signal.h
1.测试终端按键产生信号
ctrl ^ c--SIGINT --T (异常终止.不产生core文件)
ctrl ^ \--SIGQUIT --A (异常终止,产生core文件)
ctrl ^ z-- SIGSTSP --S(暂停)
注意:终端按键产生信号只能发送给前台进程组
2.系统调用:
2.1kill函数
(1)函数原

型: int kill(pid_t pid ,int sig)
(2)描述: 发送信号sig给pid代表的进程
(3)参数:
a.pid
pid>0 发送sig给pid
pid==0 发送sig给当前进程所在的进程组
pid==-1 发送sig给除一以外的所有进程
pid<0 将信号发送给其进程组ID等于pid绝对值,而且发送进程有许可权向其发送信号的所有进程。

返回值:
成功 0
失败 -1 set the errno
(4)例程:
如【*】 8#include
9 #include
10 #include
11 int main(int argc,char **argv)
12 {
13 kill(atoi(argv[1]),SIGINT);
14 return 0;
15 }
2.2raise
(1)函数原型:int raise (int sig)
(2)说明: 发送信号sig给当前的进程
raise(int sig)相当于kill(pid_t getpid,int sig )
2.3abort
函数使当前进程接收到SIGABRT 信号而异常终止
3.由软件条件产生信号
3.1alarm函数
(1)函数原型:
#include
unsigned int alarm(unsigned int seconds);
(2)描述:
使用alarm()函数可以设置一个时间值(闹钟时间),在将来的某个时刻该时间值会被超过。当所设置的时间值被超过后,产生SIGALRM信号。如果不忽略或不捕捉此信号,则其默认动作是终止该进程。
(3)产生的信号:
SIGALRM--14
(4)相关函数
setitimer();
(5)例程:
定时x秒后,闹钟到,并且用signal重新安装一个新的函数;
只能执行一次alarm
如【*】8 #include
9 #include
10 #include
11 void sfg(int signum)
12 {
13 printf("wang\n");
14 }
15 int main(int argc,char **argv)
16 {
17 signal(SIGALRM,sfg);
18 alarm(5);
19 while(1)
20 {
21 sleep(1);
22 printf("haha...\n");
23 }
24 return 0;
25 }
定时x秒后,闹钟到,并且用signal重新安装一个新的函数;
可以实现多次alarm
如【*】8 #include
9 #include
10 #include
11 #include
12 void sfg(int signum)
13 {
14 printf("wang\n");
15 }
16 int main(int argc,char **argv)
17 {
18 signal(SIGALRM,sfg);
19 struct itimerval value = {{2,0},{5,0}};
20 setitimer(ITIMER_REAL,&value,NULL);
21 while(1)
22 {
23 sleep(1);
24 printf("haha...\n");
25 }
26 return 0;

27 }
三.阻塞信号
1.信号的四个事件
信号的产生
信号在进程的pcb中注册
信号在进程的pcb中被注销

2.信号的递达
进程开始执行信号处理动作,称为信号递达
3.未决信号
信号从产生到抵达之间的状态,称之为未决信号
4.可靠信号和不可靠信号
可靠信号:在进程中,再次发送某个正处在未觉状态的信号,再次发送,的信号会处于未觉队列里
不可靠信号:在进程中,再次发送某个正处在未觉状态的信号,再次发送会被直接忽略掉
5.进程可以选择阻塞某个信号,在阻塞期间,如果向进程发送给信号,会被阻塞,换言之,该信号一直处于未决信号状态,直到进程解除对该信号的阻塞,才执行抵达的动作.

6.信号集合
1.类型:sigset_t
2.操作函数:
sigemptyset(sigset_t *set)
sigfillset(sigset_t *set)
sigaddset(sigset_t *set,int signum)
sigdelset(sigset_t *set,int signum)
sigismember(const sigset_t *set,int signum)
7.设置信号屏蔽字
sigprocmask
函数原型 int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
说明:设置当前进程的信号屏蔽字
参数:
how:
SIG BLOCK--将参数set包含的信号追加到当前进程的信号屏蔽队列中
SIG UNBLOCK--将参数set包含的信号从当前进程的信号屏蔽队列中移除
SIG SETMASK--使用参数set作为当前进程的信号屏蔽队列
set:
oldset:--返回操作之前的信号队列
结果
成功 0
失败 -1

四.如何获取信号【*】
signal
函数原型:
sighandler_t signal(int sig,sighandler_t handler)
描述:
给sig信号安装一个新的信号处理函数
参数:
1.sig-- 要安装的信号
2.handler--函数指针
a.自定义函数
b.SIG_IGN
C.SIG_DFL
返回值:
返回之前设置的信号处理函数
失败:返回 SIG_ERR
例程:
SIGKILL(kill -9)和SIGSTOP(kill -19)不能被重新定义
//形参1是形参2这个函数指针中的形参
signal(SIGINT,sfg);
【*】更改信号的方式,同时可以查看ctrl+c是信号2
8#include
9 #include
10 #include
11
12 //现存的唯一的函数指针就是函数名称
13 void sfp(int signum)
14 {
15 printf("signum:%d\n",signum);
16 }
17 int main()
18 {
19 signal(SIGINT,sfp);
20 while(1)
21 {
22 printf("haha....\n");
23 sleep(1);
24 }
25 return 0;
26 }

sigaction
函数原型: int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
描述: 设定信

号处理函数,并且设置,处理函数运行期间
3.参数:
a.signum
b.act
struct sigaction
{
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}

说明:
sa_restorer 不应该被使用
sa_handler与sa_sigaction不应该被同时使用
如果sa_flags==0,则sa_handler生效
sa_mask用于设置sa_handler执行期间需要额外屏蔽的信号
1.sa_handler执行期间,正在被处理的信号默认是被阻塞的,不需要设置
2.可以使用sa_mask添加额外的信号处理函数执行期间的信号屏蔽字,一旦信号处理函数执行完毕,使用sa_mask设置的屏蔽字会自动被解除
c.oldact
用于返回设置之前的信息
返回值:
成功 0;
失败 -1;
五.z进程的处理:【*】
方法1:忽略SIGCHLD信号
signal(SIGCHLD,SIG_LGN);
方法2:转到sfp函数中进行wait()
signal(STGCHLD,sfp);
在void sfp(int signum)
{
//全部清除僵尸进程
while(waitpid(-1,NULL,WNOHANG)>0)
{

}
//清除部分僵尸进程,另外进程忽略
waitpid(-1,NULL,WNOHANG);
}



总结:

1.信号的基本概念,如何查看
2.了解32种信号 man signal.h
了解哪些信号默认是 忽略的
了解哪些信号不能被 捕获,也不能被阻塞
3.掌握信号的发送的几种方式
kill
4.掌握信号处理函数的安装
signal
sigaction
5.掌握信号在PCB中的表示
6.掌握信号的阻塞
sigset_t
sigemptyset()
...
sigprocmask
sigpending
7.信号的未决,信号的递达
8.Z进程的处理
9.fork之后子进程对于父进程的继承(从signal角度考虑)

















































相关文档
最新文档