本帖最后由 yuanlai2010 于 2014-8-23 20:13 编辑
信号
参与Helper2416开发板助学计划心得
什么是信号
信号是UNIX和Linux系统相应某些条件而生成的一个事件.接收到该信号的进程会相应地采取一些行动。
信号生成
信号是由于某些错误条件产生的:也可以作为在进程间传递消息或修改行为的一种方式,明确的由一个进程发送给另一个进程。
信号处理
当某信号出现时,将按照以下三种方式中的一种进行处理:
1、忽略此信号
大多数信号都是按照这种方式处理,但是有两种信号却不能被忽略(SIGKILL 和 SIGSTOP)。这两种信号不能被忽略的原因是:他们向超级用户提供了一种终止或停止进程的方法。
2、执行用户希望的动作
通知内核在某种信号发生时,调用一个用户函数。在用户函数中,执行用户希望的处理
信号处理的主要方法主要有两种:一种是用简单的signal函数吗,另一种是使用信号集函数组。
3、执行系统默认动作
对大多数信号的系统默认动作是终止该进程
信号发送
发送信号的主要函数有kill和raise
区别
Kill既可以向自身发送信号,也可以向其他进程发送信号。与kill函数不同的是,raise函数是向进程自身发送信号
Raise
函数原形:int raise(int sig);
函数功能:将参数sig指定的信号发送给自身进程,使用 kill -l 命令可查看linux系统中信号。
函数返回:执行成功则返回0,如果有错误则返回-1。
参数说明:sig指定信号。
头表文件:#include
#include
Kill
函数原形:int kill(pid_t pid,int sig);
函数功能:传送信号给指定的进程,使用 kill -l 命令可查看linux系统中信号。
函数返回:执行成功则返回0,如果有错误则返回-1。
错误代码
EINVAL 参数sig 不合法
ESRCH 参数pid 所指定的进程或进程组不存在
EPERM 权限不够无法传送信号给指定进程
参数说明:sig指定的信号;pid指定的进程。
头表文件:#include
#include
函数说明:
kill()可以用来送参数sig指定的信号给参数pid指定的进程。参数pid有几种情况:
pid>0 将信号传给进程识别码为pid 的进程。
pid=0 将信号传给和当前进程相同进程组的所有进程
pid=-1 将信号广播传送给系统内所有的进程
pid<0 将信号传给进程组识别码为pid绝对值的所有进程
参数sig代表的信号:
Signal | |
| |
| 用alarm函数设置的timer超时或setitimer函数设置的interval timer超时 |
| |
| 由Solaris Thread Library内部使用,通常不会使用 |
| 进程Terminate或Stop的时候,SIGCHLD会发送给它的父进程。缺省情况下该Signal会被忽略 |
| |
| |
| |
| Solaris专用,Hiberate或者Suspended时候发送 |
| 发送给具有Terminal的Controlling Process,当terminal被disconnect时候发送 |
| |
| BSD signal。由Status Key产生,通常是CTRL+T。发送给所有Foreground Group的进程 |
| 由Interrupt Key产生,通常是CTRL+C或者DELETE。发送给所有ForeGround Group的进程 |
| |
| |
| |
| 由Solaris Thread Libray内部使用 |
| |
| 当某个事件发送给Pollable Device的时候发送 |
| Setitimer指定的Profiling Interval Timer所产生 |
| |
| 输入Quit Key的时候(CTRL+\)发送给所有Foreground Group的进程 |
| |
| |
| |
| |
| |
| |
| |
| Suspend Key,一般是Ctrl+Z。发送给所有Foreground Group的进程 |
| 当Background Group的进程尝试读取Terminal的时候发送 |
| 当Background Group的进程尝试写Terminal的时候发送 |
| 当out-of-band data接收的时候可能发送 |
| |
| |
| setitimer函数设置的Virtual Interval Timer超时的时候 |
| Solaris Thread Library内部实现专用 |
| 当Terminal的窗口大小改变的时候,发送给Foreground Group的所有进程 |
| |
| |
| |
Pause
函数原形:Int pause(void)
函数功能:Pause函数使用调用进程挂起直至捕捉到一个信号。
头表文件:#include
函数说明:只有执行了一个信号处理函数后,挂起才结束。
信号处理、执行用户希望动作的具体方法:
signal
函数原形:void (*signal(int sig, void (*fanc)(int))) (int);
或者:typedef void (*sig_t)( int );
sig_t signal(intsignum,sig_t handler);
函数功能:设置某一信号的对应动作。
函数返回:返回先前的信号处理函数指针,如果有错误则返回SIG_ERR(-1)。
参数说明:第一个参数signum指明了所要处理的信号类型,它可以取除了SIGKILL和SIGSTOP外的任何一种信号。
第二个参数handler描述了与信号关联的动作,它可以取以下三种值:
(1)一个无返回值的函数地址
此函数必须在signal()被调用前申明,handler中为这个函数的名字。当接收到一个类型为sig的信号
时,就执行handler 所指定的函数。这个函数应有如下形式的定义:
void func(int sig);
(2)SIG_IGN
这个符号表示忽略该信号,执行了相应的signal()调用后,进程会忽略类型为sig的信号。
(3)SIG_DFL
这个符号表示恢复系统对信号的默认处理。
头表文件:#include
通过signal设置好信号对应的动作后,就可以来捕获对应的信号,然后响应相应的动作。
实践代码:
- #include <signal.h>
- #include <sys/types.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- void Signal_Handler(int sig)
- {
- if(SIGINT == sig){
- printf("\nReceive signal SIGINT\n");
- signal(SIGINT, SIG_DFL);
- }
- if(SIGUSR1== sig){
- printf("Receive signal SIGUSR1\n");
- printf("This PID is %d",getpid());
- }
- }
- int main()
- {
- signal(SIGINT, Signal_Handler);
- signal(SIGUSR1,Signal_Handler);
- printf("%d Waiting for signal\n",getpid());
- raise(SIGUSR1);
- while(1){
- printf("hello world!\n");
- sleep(1);
- }
- }
复制代码
运行结果:
- [jyxtec@localhost signal]$ ./signal0
- 3273 Waiting for signal
- Receive signal SIGUSR1
- This PID is 3273hello world!
- hello world!
- hello world!
- hello world!
- ^C
- Receive signal SIGINT
- hello world!
- hello world!
- ^C
- [jyxtec@localhost signal]$
复制代码
这个例子中通过设置信号SIGUSR1对应动作答应出当前进程的PID,并使用raise给自身发送此信号,同时设置信号SIGINT(按下Ctrl + C产生此信号 如果没有设置捕获此信号的话,默认情况下会终止当前前台正在运行的进程)的对应动作来打印一条消息,打印完后把此信号的处理方式修改为默认方式,最后用Ctrl + C来终止程序运行。
论坛ID:yuanlai2010
发表时间:2014-08-23