您的位置:首页 > 编程语言

UNIX环境高级编程 第十章:信号

2018-01-16 18:45 302 查看
什么是异步事件:简单点来说,就是,你一边看书,又一边在听歌。两者之间互不干扰。编程中最常见的异步事件,就是ajax调用。页面没有刷新,但某个局部已经更新。你打开淘宝,你会发现,页面先加载,但图片过一会才加载。这就是异步的应用。

每个信号都有一个名字,这些名字都以三个字符SIG开头.在头文件:signal.h中,这些信号都被定义为正整数(信号编号 > 0)。信号是异步事件的经典实例,进程不能只是测试一个变量来判别是否发生了一个信号,而是必须告诉内核"在此信号发生时,请执行下列操作"。

当某个信号出现时,可以告诉内核按下列3种方式之一进行处理,称之为信号的处理:

1.忽略此信号。SIG_IGN。只有两种信号不能被忽略:SIGKILL和SIGSTOP。原因是:它们向内核和超级用户提供了使进程终止或停止的可靠方法。另外,如果忽略某些由硬件异常产生的信号(如非法内存引用或除以0),则进程的运行行为是未定义的。
2.捕捉信号。即通知内核在某种信号发生后,调用一个用户函数。
3.执行系统默认动作。对大多数信号的默认动作是终止该进程。
终止+core。大多数Unix系统调试程序都使用core文件检查进程终止时的状态。


主要信号简要说明:

1.函数signal

unix信号机制最简单的界面是signal函数。

#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);
//Returns: previous disposition of signal (see following) if OK, SIG_ERR on error


1.signal函数由ISO C定义。不涉及多进程、进程组以及终端I/O等,所以它对信号的定义非常含糊,以致于对Unix系统而言几乎毫无用处。

2.因为signal的语义与实现有关,所以最好使用sigaction函数代替signal函数。

3.本书中的所有实例均使用图10-18中给出的signal函数,该函数使用sigaction函数是一个平台无关、语义一致的实现。

4.signo参数是上面的信号名。func参数可以是常量SIG_IGN、SIG_DFL或接收到该信号后要调用的函数的地址,即信号处理程序的地址。signal函数的返回值是指向在此之前的信号处理程序的指针。

exec,程序启动:

当exec执行一个程序时,所有信号都被设置为它们的默认动作,除非调用exec的进程忽略该信号(则继续保持忽略)。也就是说,exec函数将原先设置为要捕获的信号都更改为默认动作,其他保持不变。因为当exec一个新程序时,信号处理程序的地址很可能在新程序中已无意义。

fork,进程创建:

当一个进程调用fork时,其子进程继承父进程的信号处理方式。因为信号处理程序的地址在子进程中是有意义的。

3.可重入函数

进程捕捉到信号并对其进行处理时,进程正在执行的正常指令序列就被信号处理程序临时中断,它首先执行该信号处理程序中的指令。但是,在信号处理程序中,不能判断捕捉到信号时进程执行到何处:

如果进程正在执行malloc,而在信号处理程序中又再次调用malloc,这时会?

如果进程正在执行getpwnam,这是将其结果存放在静态存储单元中的函数,而在信号处理程序中又再次调用getpwnam,这时会?

4.函数kill和raise

kill函数将信号发送给进程或进程组

raise函数则允许进程向自身发送信号。

#include <signal.h>
int kill(pid_t pid, int signo);
int raise(int signo);
Both return: 0 if OK, −1 on error
raise(signo); 等价于 kill(getpid(), signo);

kill的pid参数有以下4种情况:
pid > 0,发送给进程ID为pid的进程
pid == 0,发送给与发送进程属于同一进程组的所有进程
pid < 0,发送给其进程组ID等于pid绝对值,而且发送进程具有权限向其发送信号的所有进程
pid == -1,发送给发送进程具有权限向它们发送信号的所有进程


关于发送信号的权限:

(1)超级用户可将信号发送给任一进程。

(2)非超级用户,其基本规则是发送者的实际用户ID或有效用户ID必须等于接收者的实际用户ID或有效用户ID。

特例:如果被发送的信号是SIGCONT,则进程可以将它发送给属于同一会话的任一其他进程。

5.函数alarm、pause

当定时器超时时,产生SIGALRM信号。信号由内核产生:

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
Returns: 0 or number of seconds until previously set alarm


每个进程只能有一个闹钟时间。多次调用alarm以新值代替旧值,并返回旧值的余留值。参数为0,则取消以前的闹钟。

pause函数使调用进程挂起直到捕捉到一个信号:

#include <unistd.h>
int pause(void);
Returns: −1 with errno set to EINTR


只有执行了一个信号处理程序并从其中返回时,pause才返回。返回-1,errno设置为EINTR。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: