技术开发 频道

Linux编程:信号篇

第3节 高级信号处理

    在我们最后的讨论中,将涉及信号处理的一些高级话题,如信号挂起和等待一个信号等。


    获得当前信号掩码

    进程当前被阻塞的信号集被称作“信号掩码”。为了获得或改变当前信号掩码 ,可以调用 sigprocmask ()函数∶

int sigprocmask(int mode, const sigset_t * newmask, sigset_t

oldmask);
    第一个参数可以取下列值∶

SIG_BLOCK - -将newmask中的全部信号加入到当前信号掩码中。
SIG_UNBLOCK - -从当前信号掩码中,将newmask的所有信号全部删除
SIG_SETMASK -仅阻塞newmask内的信号;将其余的信号解除阻塞。

    如果oldmask不是NULL,那么就把当前的信号掩码( sigprocmask被调用之前)拷贝给它。下列代码可用于检索一个进程的当前信号掩码∶

sigset_t oldmask;
sigemptyset(&oldmask); sigprocmask(SIG_BLOCK, NULL, &oldmask);


阻塞信号

    我们经常需要在一段程序代码中阻塞进入的信号,而这段代码和信号的handler却可能在同时修改数据。对于一个SIGALRM信号,考虑下面的handler∶

char *Flags=someString; /*一个全局字符串*/
void handleAlarm(int sig){ free(someString); someString=NULL; }

    当程序正在处理Flags时,如果一个SIGALRM信号被送达,这时将发生什么?

for (i=0; i<10; ++i)
Flags[i]=CLEAR;

    后果是灾难性的——循环语句正在往其中写数据,而handler却释放了Flags。为避免上述情况,在进入循环之前我们必须阻塞SIGALRM,过后再为其解除阻塞。

sigset_t alrm;
sigemptyset(&alrm); sigaddset(&alrm, SIGALRM); sigprocmask(SIG_BLOCK, &alrm, NULL); /*阻塞*/ for (i=0; i<10; ++i) /*安全地处理Flags*/ Flags[i]=OK; sigprocmask(SIG_UNBLOCK, &alrm, NULL);/*解除阻塞*/

    为了列出所有当前挂起的信号,可以调用sigpending ()函数∶

int sigpending(sigset_t * pending);

    调用sigpending ()后, pending将包含全部当前闭塞信号。

等待信号

    基于事件的应用程序,总是等待一个信号的出现,直到信号出现才开始运行。为此,要使用<unistd.h>中的pause()函数:

int pause(void);

    直到一个信号已经投递给该进程之后,pause ()才返回。如果存在一个与信号匹配的handler, 那么handler将在pause ()返回之前执行。换句话说,你可以调用在<signal.h>中的sigsuspend (),如同下述∶

int sigsuspend(const sigset_t * tempmask);

    sigsuspend ()暂停该进程直到一个信号已经被投递。但是不同于pause (),在等待一个信号出现之前,它临时设置该进程的掩码为tempmask。一旦信号出现,该进程的信号掩码就会恢复为sigsuspend ()被调用之前的值。同时,pause ()(它和 sigsuspend ()两者都返回- 1)将设定errno为EINTR。

0
相关文章