1.9.信号(Signals)
信号是通知一个进程已发生某种条件的一种技术(a technique used to notify a process that some condition has occurred)。例如,若某一进程执行除法操作,其除数为0,则名为SIGFPE(浮点数异常floating-point exception)的信号将被发送给该进程。进程如何处理信号有三种选择:
(1) 忽略该信号。对于表示(denote)一个硬件异常的信号,比如除数为0或者访问到了继承的地址空间之外的内存,因为这些异常产生的后果不确定,所以不推荐使用这种处理方式。
(2) 让系统默认行为(default action)进行处理。对于除数为0的情况,系统默认行为是终止该进程。
(3) 提供一个函数,信号发生时则调用该函数(这叫做捕捉信号catch the signal)。使用我们自己提供的函数,我们将能知道什么时候产生了信号,并能按我们所希望的方式处理它。
很多情况下会产生信号。有两种键盘方式,分别称为中断键(interrupt key,通常是DELETE键或Ctrl-C)和退出键(quit key,通常是Ctrl-/),它们被用于中断当前运行的进程。另一种产生信号的方法是调用kill函数。在一个进程中调用此函数就可向另一个进程发送一个信号。当然这种方法也有些限制:当向另一个进程发送信号时,我们必须是该接受信号进程的所有者或者超户。
Example
回忆一下bare-bones shell例子程序(figure1.7)。如果调用此程序,然后键入中断键,则执行此程序的进程终止。产生这种后果的原因是:对于此信号SIGINT的系统默认动作是终止此进程。因为该进程没有告诉kernel对此信号作何处理(即没有按照前述的第三种方法提供一个函数),所以系统按默认方式终止该进程。
为了能捕捉到该信号,figure1.7需要调用signal函数,来指定当SIGINT信号产生时要调用的函数名。因此编写了名为sig_int的函数,当其被调用时,它只是打印一条消息,然后打印一个新提示符。在程序figure1.7中加了11行构成了程序figure1.10(添加的11行以行首的+号指示)。因为大多数重要的应用程序都将使用信号,所以第10章将详细介绍信号。
Figure 1.10. Read commands from standard input and execute them
#include "apue.h"
#include <sys/wait.h>
+ static void sig_int(int); /* our signal-catching function */
+
int
main(void)
{
char buf[MAXLINE]; /* from apue.h */
pid_t pid;
int status;
+ if (signal(SIGINT, sig_int) == SIG_ERR)
+ err_sys("signal error");
+
printf("%% "); /* print prompt (printf requires %% to print %) */
while (fgets(buf, MAXLINE, stdin) != NULL) {
if (buf[strlen(buf) - 1] == "/n")
buf[strlen(buf) - 1] = 0; /* replace newline with null */
if ((pid = fork()) < 0) {
err_sys("fork error");
} else if (pid == 0) { /* child */
execlp(buf, buf, (char *)0);
err_ret("couldn't execute: %s", buf);
exit(127);
}
/* parent */
if ((pid = waitpid(pid, &status, 0)) < 0)
err_sys("waitpid error");
printf("%% ");
}
exit(0);
}
+
+ void
+ sig_int(int signo)
+ {
+ printf("interrupt/n%% ");
+ }
-------------------------------------------------------------------
自己写的singa.cpp
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#define BUFFSIZE 90
static void sig_int(int); /* our signal-catching function */
int
main(void)
{
int n = 0;
char buf[BUFFSIZE];
if (signal(SIGINT, sig_int) == SIG_ERR)
cout<<"signal error"<<endl;
while( (n = read(STDIN_FILENO,buf,BUFFSIZE)) > 0)
if (write(STDOUT_FILENO,buf,n) != n)
cout<<"write error."<<endl;
exit(0);
}
void
sig_int(int signo)
{
printf("interrupt/n%% ");
}
[lizl@localhost apue_code]$ ./signal.out
abc
abc
interrupt 键入ctrl-c
dd
dd
% interrupt 键入ctrl-c
% interrupt 键入ctrl-c
% [lizl@localhost apue_code]$ 键入ctrl-d
-------------------------------------------------------------------