Chinaunix首页 | 论坛 | 博客
  • 博客访问: 388700
  • 博文数量: 83
  • 博客积分: 1650
  • 博客等级: 上尉
  • 技术积分: 861
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-18 18:22
文章分类
文章存档

2021年(1)

2016年(1)

2015年(2)

2014年(3)

2013年(12)

2012年(16)

2011年(18)

2010年(30)

分类: LINUX

2010-11-08 00:53:02

信号通信

信号是UNIX 中所使用的进程通信的一种最古老的方法。它是在软件层次上对中断机制

的一种模拟,是一种异步通信方式。信号可以直接进行用户空间进程和内核进程之间的交互,

内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。它可以在任何时候发给某

一进程,而无需知道该进程的状态。如果该进程当前并未处于执行态,则该信号就由内核保

存起来,直到该进程恢复执行再传递给它为止;如果一个信号被进程设置为阻塞,则该信号

的传递被延迟,直到其阻塞被取消时才被传递给进程。

细心的读者是否还记得,在第2 kill 命令中曾讲解到“l”选项,这个选项可以列

出该系统所支持的所有信号列表。在笔者的系统中,信号值在32 之前的则有不同的名称,

而信号值在32 以后的都是用“SIGRTMIN”或“SIGRTMAX”开头的,这就是两类典型

的信号。前者是从UNIX 系统中继承下来的信号,为不可靠信号(也称为非实时信号);

后者是为了解决前面“不可靠信号”的问题而进行了更改和扩充的信号,称为“可靠信

号”(也称为实时信号)。那么为什么之前的信号不可靠呢?这里首先要介绍一下信号的

生命周期。

一个完整的信号生命周期可以分为3 个重要阶段,这3 个阶段由4 个重要事件来刻

画的:信号产生、信号在进程中注册、信号在进程中注销、执行信号处理函数,如图

8.6 所示。相邻两个事件的时间间隔构成信号生命周期的一个阶段。要注意这里的信号

处理有多种方式,一般是由内核完成的,当然也可以由用户进程来完成,故在此没有明

确画出。

一个不可靠信号的处理过程是这样的:如果发现该信号已经在进程中注册,那么就忽略

该信号。因此,若前一个信号还未注销又产生了相同的信号就会产生信号丢失。而当可靠信

号发送给一个进程时,不管该信号是否已经在进程中注册,都会被再注册一次,因此信号就

不会丢失。所有可靠信号都支持排队,而不可靠信号则都不支持排队。

用户进程对信号的响应可以有3 种方式。

· 忽略信号,即对信号不做任何处理,但是有两个信号不能忽略,即SIGKILL

SIGSTOP

· 捕捉信号,定义信号处理函数,当信号发生时,执行相应的处理函数。

· 执行缺省操作,Linux 对每种信号都规定了默认操作。

 

信 号 名 含 义 默 认 操 作

SIGHUP

该信号在用户终端连接(正常或非正常)结束时发出,

通常是在终端的控制进程结束时,通知同一会话内的各

个作业与控制终端不再关联

SIGINT 该信号在用户键入INTR字符(通常是Ctrl-C)时发出,终

端驱动程序发送此信号并送到前台进程中的每一个进程

SIGQUIT 该信号和SIGINT类似,但由QUIT字符(通常是Ctrl-\

来控制

SIGILL

该信号在一个进程企图执行一条非法指令时(可执行文

件本身出现错误,或者试图执行数据段、堆栈溢出时)

发出

SIGFPE

该信号在发生致命的算术运算错误时发出。这里不仅包

括浮点运算错误,还包括溢出及除数为0 等其他所有的

算术的错误

SIGKILL 该信号用来立即结束程序的运行,并且不能被阻塞、处

理和忽略

SIGALRM 该信号当一个定时器到时的时候发出终止

SIGSTOP 该信号用于暂停一个进程,且不能被阻塞、处理或忽略暂停进程

SIGTSTP 该信号用于交互停止进程,用户可键入SUSP字符时(通

常是Ctrl+Z)发出这个信号

SIGCHLD 子进程改变状态时,父进程会收到这个信号忽略

SIGABORT

 

信号发送与捕捉

发送信号的函数主要有kill()raise()alarm()以及pause(),下面就依次对其进行介绍。

1kill()raise()

1)函数说明

kill 函数同读者熟知的kill 系统命令一样,可以发送信号给进程或进程组(实际上,kill

系统命令只是kill函数的一个用户接口)。这里要注意的是,它不仅可以中止进程(实际上发

SIGKILL信号),也可以向进程发送其他信号。

kill函数所不同的是,raise函数允许进程向自身发送信号。

(1)   函数格式

所需头文件#include

#include

 

函数原型int kill(pid_t pid,int sig)

 pid

正数:要发送信号的进程号

0: 信号被发送到所有和pid进程在同一个进程组的进程

-1:信号发给所有的进程表中的进程(除了进程号最大的进程外)

 

 

sig:信号
函数返回值

成功:0

出错:-1

raise函数的语法要点。

所需头文件#include

#include

 

函数原型int raise(int sig)

函数传入值sig:信号

函数返回  成功:0

出错:-1

 

3)函数实例

下面这个示例首先使用fork创建了一个子进程,接着为了保证子进程不在父进程调用kill

之前退出,在子进程中使用raise 函数向子进程发送SIGSTOP 信号,使子进程暂停。接下来

再在父进程中调用kill 向子进程发送信号,在该示例中使用的是SIGKILL,读者可以使用其

他信号进行练习。

/*kill.c*/

#include

#include

#include

#include

#include

int main()

{

pid_t pid;

int ret;

/*创建一子进程*/

if((pid=fork())<0){

perror("fork");

exit(1);

}

if(pid == 0){

/*在子进程中使用raise函数发出SIGSTOP信号*/

raise(SIGSTOP);

exit(0);

}

else{

/*在父进程中收集子进程发出的信号,并调用kill函数进行相应的操作*/

printf("pid=%d\n",pid);

if((waitpid(pid,NULL,WNOHANG))==0){

if((ret=kill(pid,SIGKILL))==0)

printf("kill %d\n",pid);

else{

perror("kill");

}

}

}

}

该程序运行结果如下所示:

[root@(none) tmp]# ./kill

pid=15317

kill 15317

2alarm()pause()

1)函数说明

alarm 也称为闹钟函数,它可以在进程中设置一个定时器,当定时器指定的时间到时,

它就向进程发送SIGALARM 信号。要注意的是,一个进程只能有一个闹钟时间,如果在调

alarm之前已设置过闹钟时间,则任何以前的闹钟时间都被新值所代替。

pause 函数是用于将调用进程挂起直至捕捉到信号为止。这个函数很常用,通常可以用

于判断信号是否已到。

(2)   函数格式

   所需头文件#include

函数原型unsigned int alarm(unsigned int seconds)

函数传入值seconds:指定秒数

函数返回值

成功:如果调用此alarm()前,进程中已经设置了闹钟时间,则返回上一个闹钟

时间的剩余时间,否则返回0

出错:-1

pause函数的语法要点。

所需头文件#include

函数原型int pause(void)

函数返回值-1,并且把error 值设为EINTR

 

3)函数实例

该实例实际上已完成了一个简单的sleep函数的功能,由于SIGALARM默认的系统动作

为终止该进程,因此在程序调用pause之后,程序就终止了。如下所示:

/*alarm.c*/

#include

#include

#include

int main()

{

int ret;

/*调用alarm定时器函数*/

ret=alarm(5);

pause();

printf("I have been waken up.\n",ret);

}

[root@(none) tmp]#./alarm

闹钟

阅读(675) | 评论(1) | 转发(0) |
0

上一篇:exec函数族

下一篇:线程(1)

给主人留下些什么吧!~~

chinaunix网友2010-11-08 15:34:16

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com