在早期的UNIX版本中(如V7),信号是不可靠的。不可靠在这里指的是,信号可能会丢失:一个信号发生了,但进程却可能一直不知道这一点。

同时,进程对信号的控制能力也很差,它能捕捉信号或忽略它。有时用户希望通知内核阻塞某个信号:不要忽略该信号,在其发生时记住它,然后在进程做好了准备时再通知它。这种阻塞信号的能力当时并不具备。

AMY : 原书应该意思是进程只能捕捉或忽略信号不具有阻塞并通知信号到来的能力。

4.2BSD对信号机制进行了更改,提供了被称为可靠信号的机制。然后,SVR3也修改了信号机制,提供了System V可靠信号机制。POSIX.1选择了BSD模型作为其标准化的基础。

早期版本中的一个问题是在进程每次接到信号对其进行处理时,随即将该信号动作重置为默认值(在前面运行图10-2程序时,每种信号只捕捉一次,从而回避了这一点)。

在描述这些早期系统的编程书籍中,有一个经典实例,它与如何处理中断信号相关,其代码与下面所示的相似:

int sig_int(); // mysignal handling function
.
.
.
singal(SIGINT,sig_int) // establish handler
.
.
.
sig_int(){
    signal(SIGINT,sig_int); // re establish handler for next time
    .
    .
    . //process the signal
}

这段代码的一个问题是:在信号发生之后到信号处理程序调用signal函数之间有一个时间窗口。在此段时间中,可能发生另一次中断信号。第二个信号会造成执行默认动作,而对中断信号的默认动作是终止该进程。这种类型的程序段在大多数情况下会正常工作,使我们认为它们是正确无误的,而实际上并非如此。

这些早期版本的另一个问题是:在进程不希望某种信号发生时,它不能关闭该信号。进程能做的一切就是忽略该信号。有时希望通知系统“阻止下列信号发生,如果它们确实产生了,请记住它们。”能够显现这种缺陷的的一个经典实例是下列程序段,它捕捉一个信号,然后设置一个表示该信号已发生的标志:

int sig_int(); // my signalhandling function
int sig_int_flag; // set nozero when signal occurs

main(){
    signal(SIGINT,sigint) // establish handler
    ...
    while(sig_int_flat == 0)
        pause; // go to sleep, waiting for signal
        ...
}
sig_int(){
    signal(SIGINT,sig_int) // re establish handler for next time
    sig_int_flag = 1; // set flag for main loop to examine
}

其中,进程调用 pause 函数使自己休眠,直到捕捉到一个信号。

?:当捕捉到信号时,信号处理程序将标志 sig_int_flag 设置为非 0 值。从信号处理程序返回后,内核自动将该进程唤醒,它检测到该标志为非0,然后执行它所需做的。

但是这里有一个时间窗口,在此窗口中操作可能失误。如果在测试sig_int_flag之后、调用pause之前发生信号,则此进程在调用pause时可能将永久休眠(假定此信号不会再次产生)。于是,这次发生的信号也就丢失了。这是另一个例子,某段代码并不正确,但是大多数时间却能正常工作。要查找并排除这种类型的问题很困难。

results matching ""

    No results matching ""