曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 8698|回复: 6
打印 上一主题 下一主题

信号概述(Unix && Linux)

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34387
跳转到指定楼层
楼主
发表于 2009-5-31 15:34:34 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
信号是 UNIX 中所使用的进程通信的一种古老方法。它是在软件层次上对中断机制的一种模拟,是一种异步通信方式。信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。它可以在任何时候发给某一进程,而无需知道该进程的状态。如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它为止;如果一个信号被进程设置为阻塞,则该信号传递被延迟,直到其阻塞被取消时传递给进程。

使用 kill -l 指令可以列出本机系统所支持的所有信号列表
beyes@linux-beyes:~> kill -l
 1) SIGHUP     2) SIGINT     3) SIGQUIT     4) SIGILL
 5) SIGTRAP     6) SIGABRT     7) SIGBUS     8) SIGFPE
 9) SIGKILL    10) SIGUSR1    11) SIGSEGV    12) SIGUSR2
13) SIGPIPE    14) SIGALRM    15) SIGTERM    16) SIGSTKFLT
17) SIGCHLD    18) SIGCONT    19) SIGSTOP    20) SIGTSTP
21) SIGTTIN    22) SIGTTOU    23) SIGURG    24) SIGXCPU
25) SIGXFSZ    26) SIGVTALRM    27) SIGPROF    28) SIGWINCH
29) SIGIO    30) SIGPWR    31) SIGSYS    34) SIGRTMIN
35) SIGRTMIN+1    36) SIGRTMIN+2    37) SIGRTMIN+3    38) SIGRTMIN+4
39) SIGRTMIN+5    40) SIGRTMIN+6    41) SIGRTMIN+7    42) SIGRTMIN+8
43) SIGRTMIN+9    44) SIGRTMIN+10    45) SIGRTMIN+11    46) SIGRTMIN+12
47) SIGRTMIN+13    48) SIGRTMIN+14    49) SIGRTMIN+15    50) SIGRTMAX-14
51) SIGRTMAX-13    52) SIGRTMAX-12    53) SIGRTMAX-11    54) SIGRTMAX-10
55) SIGRTMAX-9    56) SIGRTMAX-8    57) SIGRTMAX-7    58) SIGRTMAX-6
59) SIGRTMAX-5    60) SIGRTMAX-4    61) SIGRTMAX-3    62) SIGRTMAX-2
63) SIGRTMAX-1    64) SIGRTMAX   
由上面可以看到,信号值在 32 之前的都有不同的名称,而信号值在 32 以后的都是用  SIGRTMINSIGRTMAX 开头,这就是两类典型的信号。前者是从 UNIX 系统中继承下来的信号,为不可靠信号( 也称为非实时信号 );后者是为了解决前面 “不可靠信号” 的问题而进行了更改和扩充的信号,称为“可靠信号”( 也称为实时信号 )。为什么之前的信号不可靠呢?这里先从信号的生命周期看起。

一个完整的信号生命周期可以分为 3 个重要阶段,这 3 个阶段由 4 个重要事件来刻画的:信号产生、信号在进程中注册、信号在进程中注销、执行信号处理函数:

上图中,相邻的两个事件间隔构成信号生命周期的一个阶段。要注意这里的信号处理有多种方式,一般是由内核完成,当有也可以由用户进程来完成。

一个不可靠的处理过程是这样的:如果发现该信号已经在进程中注册,那么就忽略该信号。因此,若前一个信号还未注销又产生了相同的信号就会产生信号丢失。而当可靠信号发送给一个进程时,不管该信号是否已经在进程中注册,都会被再注册一次,因此信号就不会丢失。所有可靠信号都支持排队,而不可靠信号都不支持排队。

注意
这里的信号的产生、注册、注销等都是指信号的内部实现机制,而不是信号的函数实现的。

用户进程对信号的响应可以有 3 种方式:
      忽略信号,即对信号不做任何处理,但是有两个信号不能忽略,即 SIGKILL 及 SIGSTOP
      捕捉信号,定义信号处理函数,当信号发生时,执行相应的处理函数。
      执行缺省操作,Linux 对每种信号都规定了默认操作。

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34387
沙发
 楼主| 发表于 2009-7-2 01:40:21 | 只看该作者

信号的来源

信号的来源有多种方式,按照产生条件的不同可以分为 “硬件” 和 “软件” 两种方式:

1、硬件方式
      当用户在终端上按下某些键时,将产生信号。如按下 ctrl + c 组合键后将产生一个 SIGINT 信号。
      硬件异常产生信号:除数为0、无效的存储访问等。这些事件通常由硬件( 如 CPU )检测到,并将其通知给 linux 操作系统内核,然后由内核产生相应的信号,并把信号发送给该事件发生时正在运行的程序。
2、软件方式
      用户在终端下调用 kill 命令向进程发送任意信号。
      进程调用 kill 或 sigqueue 函数发送信号
      当检测到某种软件已经具备时发出信号,如由 alarm 或 settimer 设置的定时器超时时将发生 SIGALRM 信号

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34387
板凳
 楼主| 发表于 2009-7-2 02:01:47 | 只看该作者

可靠信号与不可靠信号

SIGHUP ( 1 号 ) 至 SIGSYS( 31 号 ) 之间的信号都是继承自 UNIX 系统,是不可靠信号。
Linux 根据 POSIX.4 标准定义了 SIGRTMIN ( 33 号 ) 与 SIGRTMAX ( 64 号 ) 之间的信号,它们都是可靠信号,也称为实时信号。linux 底下没有 16 和 32 号信号。

在 Linux 系统中,信号的可靠性是指信号是否会丢失,或者说该信号是否支持排队。当导致产生信号的时间发生时,内核就产生一个信号。信号产生后,内核通常会在进程表中设置某种形式的标志。当内核设置了这个标志,我们就说内核向一个进程递送了一个信号。信号产生 ( gernerate ) 和 递送 ( delivery ) 之间的时间间隔,称为信号未决 (pending) 。

进程可以调用 sigpending 将信号设置为阻塞,如果为进程产生了一个阻塞的信号( 拒绝递送请求 ),而对该信号的动作是捕捉该信号( 即不忽略信号 ),则内核将为该进程的此信号保持为未决状态,直到该进程对此信号接触阻塞或将对此信号的相应更改为忽略。如果在进程接触对某个信号的阻塞之前,这种喜好发生多次,那么如果信号被递送多次 ( 即信号在未决信号队列里面排队 ),则称之为可靠信号;只被递送一次的信号称为不可靠信号。

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34387
地板
 楼主| 发表于 2009-7-2 02:04:58 | 只看该作者

信号的优先级

信号实质上是软中断,中断有优先级,信号也有优先级。
如果一个进程有多个未决信号,则对于同一个未决的实时信号,内核将按照发送的顺序来递送信号。如果存在多个未决的实时信号,则值 ( 或者说编号 )越小的越先被递送。如果既存在不可靠信号,又存在可靠信号 ( 实时信号 ),虽然 POSIX 对这一情况没有明确规定,但 linux 系统和大多数遵循 POSIX 标准的操作系统一样,将优先递送不可靠信号。

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34387
5#
 楼主| 发表于 2012-7-25 08:38:18 | 只看该作者

SIGTTIN 和 SIGCONT 信号

当一个后台进程组中的进程试图读其控制终端时,终端驱动程序产生此信号。比如运行下面命令:
[beyes[url=u.php?uid=10]@beyes  [/url]   ~]$ cat > tmp.txt &
[1] 1800

[1]+  已停止               cat > tmp.txt
[beyes@beyes   ~]$ fg
cat > tmp.txt
hello linux
[beyes@beyes   ~]$ cat tmp.txt
hello linux
在输完 cat > tmp.txt & 命令当并按下回车键后, shell 在后台启动 cat 进程,但是此时 cat 试图读取标准输入(控制终端)时,终端驱动程序将检测到这是个后台作业,于是会将 SIGTTIN 信号送到该后台作业。shell 检测到其子进程的状态改变(wait() 或 waitpid()),并通知我们该作业已被停止。接着,使用 fg 命令将该停止的作业送入前台运行,此时改作业被置入前台进程组,并将继续信号 (SIGCONT) 送给该进程组。当作业位于前台时,它可以读控制终端了。

前台作业和后台作业容易理解,在一个会话中,任一时刻,只能有一个前台作业,而可以有多个后台作业。这好比一个公司,一个公司中,往往有一个前台文员负责接待,而公司内部(后台)可以有多个部门负责不同的工作(后台作业)。如果有客户来访,应当先由前台文员负责接待登记,公司内部员工不能直接会见客户(试图读取终端),如果试图去做,那么被老板监控设施监控到,然后会阻止这一行为(发送 SIGTTIN 信号)。如果得到老板的允许(fg 命令运行,发送 SIGCONT 信号),那么后台的员工也可以走到前台去接待来访客户.

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34387
6#
 楼主| 发表于 2012-8-2 01:33:59 | 只看该作者

SIGQUIT 信号

当用户在终端上按退出键 (Ctrl + \\) 时,产生该信号,并送至前台进程组中的所有进程。此信号不仅会终止前台进程组,同时还会产生一个 core 文件。

可以通过下面命令做上面的实验:
#ulimit -S -c unlimited     //设置后可以在当前目录下看到生成的 core.xxx 文件
# cat /dev/urandom
....按下 Ctrl + \\ 组合键...

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34387
7#
 楼主| 发表于 2012-8-6 11:09:08 | 只看该作者

SIGALRM 信号

在调用 alarm() 函数设置的计时器超时时会产生该信号,另外如果 setitimer() 设置的间隔时间超时时也能产生该信号。默认情况下,SIGALRM 信号会结束进程。

alarm() 函数可参考:http://www.groad.net/bbs/read.php?tid-7329.html

setitimer() 函数可参考:http://www.groad.net/bbs/read.php?tid-3337.html
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-5-19 10:31 , Processed in 0.067797 second(s), 21 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表