我有这个代码,我必须重复等待信号程序块。我的老师希望我们使用sigsuspend和面具而不是暂停或睡眠。我不熟悉sigsuspend或mask,我知道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);
}
答案 0 :(得分:8)
简单的入门方法是只用空掩码调用sigsuspend
(即任何信号都可以唤醒程序):
sigset_t myset;
(void) sigemptyset(&myset);
while (1) {
(void) printf("I'm running, waiting for a signal...\n");
(void) sigsuspend(&myset);
}
下一步是使用sigprocmask
来禁用两个处理过的信号(SIGINT
和SIGQUIT
),而不是在{{1}中等待它们时}。然后你会使用从sigsuspend
获得的“旧面具”,而不是悬挂时的空面具。
答案 1 :(得分:7)
GNU libc manual说明似乎清晰透彻:
功能:int sigsuspend(const sigset_t * set)
此函数用set替换进程的信号掩码,然后暂停 处理直到传递其行动的信号 要么终止进程,要么调用信号处理功能。 换句话说,该程序有效地暂停,直到其中一个 不属于集合成员的信号到达。
如果通过传递调用处理函数的信号唤醒进程, 并且处理函数返回,然后是sigsuspend 也回来了。
只要sigsuspend正在等待,掩码就会保持设置状态。功能sigsuspend 总是恢复以前的信号掩码 回报。
返回值和错误条件与暂停相同。
使用sigsuspend,您可以替换中的暂停或睡眠循环 上一节完全可靠:
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的掩码允许 通过传递其他类型的信号唤醒的过程,如 好的,例如,工作控制信号。如果这个过程被a唤醒了 没有设置usr_interrupt的信号,它只是暂停自己 直到“正确”的信号最终到来。
这项技术需要更多的准备工作,但事实如此 对于您想要使用的每种等待标准,只需要一次。该 实际等待的代码只有四行。
答案 2 :(得分:1)
-通过使用 sigsuspend() API,一个进程可以暂停它的执行,直到任何一个 信号是从一组信号中传递出来的。
等待信号的干净可靠的方法是阻塞它并 然后使用 sigsuspend。
通过在循环中使用 sigsuspend,可以等待某种 信号同时允许其他类型的信号由它们处理 处理程序。
它允许进程暂停执行,直到收到一个 mask指向的集合中不存在的信号。
语法:int sigsuspend(sigset_t *mask);
它用一个新的掩码临时替换当前的掩码并 一旦信号处理程序返回,就会恢复。
由于 sigsuspend() 无限期地暂停线程执行,所以有 没有成功完成返回值,失败返回-1。
这个程序确保 SIGKILL 和 SIGTERM 程序在临界区执行时信号被阻塞 并在发出 SIGINT 信号后恢复执行 执行相应的信号处理程序 */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
int cs = 0;
int value = 5;
/* This is the function called on receipt of signal(cntl+c) */
void sig_handler (int sig)
{
printf("\n This is signal handler for signal %d\n", sig);
cs =1;
}
int main()
{
struct sigaction act;
act.sa_handler = sig_handler;
sigemptyset (&act.sa_mask);
sigaddset (&act.sa_mask, SIGPIPE);
act.sa_flags = 0;
sigset_t sig_term_kill_mask;
sigaddset (&sig_term_kill_mask, SIGTERM);
sigaddset (&sig_term_kill_mask, SIGKILL);
sigaction (SIGINT, &act, NULL);
/* Critical section */
value++;
printf ("\n Value is %d\n", value);
while (cs == 0)
sigsuspend (&sig_term_kill_mask);
printf("\n Return from suspended successful\n");
int ret = sigismember (&act.sa_mask, SIGPIPE);
if (ret)
printf("\n Old Mask that is SIGPIPE is restored after return from sigsuspend\n");
else
printf("\n Old Mask that is SIGPIPE failed to restored after return from sigsuspend\n");
return 0; }
输出:
gcc sigsuspend.c
./a.out
值为 6 ^C 这是信号 2 的信号处理程序
暂停成功返回
从 sigsuspend 返回后恢复为 SIGPIPE 的旧 Mask