我有这个代码,我必须让程序块反复等待信号.我的老师希望我们使用sigsuspend和面具而不是暂停或睡眠.我不熟悉的sigsuspend或面罩,我知道,sigsuspend()临时替换用面膜给出的面具调用进程的信号屏蔽,然后挂起过程,直到传递的信号,其作用是调用信号处理程序或终止进程.但是我该如何实现呢.
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
unsigned Conta = 0;
void mypause(int sign)
{
switch (sign)
{
case SIGINT:
printf("You've pressed ctrl-C\n");
printf("I'm running waiting for a signal...\n");
Conta++;
break;
case SIGQUIT:
printf("You've pressd ctrl-\\n");
printf("Number of times you've pressed CTRL-C: %d", Conta);
exit(0);
break;
}
}
int main()
{
alarm(3);
printf("I'm Alive\n");
signal(SIGINT, mypause);
signal(SIGQUIT, mypause);
printf("I'm running, waiting for a signal...\n");
while (1)
{
}
return (0);
}
Run Code Online (Sandbox Code Playgroud)
开始的简单方法是sigsuspend使用空掩码调用(即,任何信号都可以唤醒程序):
sigset_t myset;
(void) sigemptyset(&myset);
while (1) {
(void) printf("I'm running, waiting for a signal...\n");
(void) sigsuspend(&myset);
}
Run Code Online (Sandbox Code Playgroud)
下一步是用来sigprocmask禁用你的两个处理信号(SIGINT和SIGQUIT),而不是在你等待它们时sigsuspend.然后你会使用sigprocmask悬挂时从空掩码中获取的"旧掩码" .
在libc中手动GNU描述似乎很清楚和透彻:
功能:int sigsuspend(const sigset_t*set)
此函数用set替换进程的信号掩码,然后暂停进程,直到传递一个信号,其动作是终止进程或调用信号处理函数.换句话说,程序被有效地暂停,直到其中一个非集合成员的信号到达.
如果通过传递调用处理函数的信号唤醒进程,并且处理函数返回,则sigsuspend也会返回.
只要sigsuspend正在等待,掩码就会保持设置.函数sigsuspend在返回时始终恢复先前的信号掩码.
返回值和错误条件与暂停相同.
使用sigsuspend,您可以使用完全可靠的内容替换上一节中的暂停或睡眠循环:
Run Code Online (Sandbox Code Playgroud)sigset_t mask, oldmask; ... /* Set up the mask of signals to temporarily block. */ sigemptyset (&mask); sigaddset (&mask, SIGUSR1); ... /* Wait for a signal to arrive. */ sigprocmask (SIG_BLOCK, &mask, &oldmask); while (!usr_interrupt) sigsuspend (&oldmask); sigprocmask (SIG_UNBLOCK, &mask, NULL);最后一段代码有点棘手.这里要记住的关键点是,当sigsuspend返回时,它会将进程的信号掩码重置为原始值,即调用sigsuspend之前的值 - 在这种情况下,SIGUSR1信号再次被阻止.第二次调用sigprocmask是明确解除阻塞此信号所必需的.
另外一点:你可能想知道为什么while循环是必要的,因为程序显然只等待一个SIGUSR1信号.答案是传递给sigsuspend的掩码允许通过传递其他类型的信号唤醒进程,例如作业控制信号.如果该过程被一个未设置usr_interrupt的信号唤醒,它只会再次暂停,直到"正确"的信号最终到达.
这种技术需要更多的准备工作,但对于您想要使用的每种等待标准,只需要一次.实际等待的代码只有四行.