2014-09-28 44 views
-3

我正在写一个程序,每5秒发送一个信号(警报)给自己。我也希望如果用户键入被忽略的终端“kill -ALRM PID”。如果我理解的信号来电,我的程序应该这样做,但是,当我使用该命令从终端proram认为这是它的一个警报和犯规忽略它C编程 - 为什么这个信号不被忽略?

int s = 0; 
void alarm_func(int s) { 
    s = s + 10; 
    char buff[256]; 
    sprintf(buff, "ALARM pid=%d, %d seconds, getpid(), s); 
    write(1, buff, strlen(buff));  
} 

int main(int argc, char* argv[]) { 
    int k = 1; //just a different value from 0 
    if (k == 0) signal(SIGALRM, alarm_func); 
    else signal(SIGALRM, SIG_IGN); //this should ignore the terminal-created alarm (?) 
    while (s<100) { 
     k = alarm(10); 
     pause(); 
    } 
    exit(1); 
} 

非常感谢

编辑:我的prgram应该每10秒发送一次信号给自己100秒,即10次。但是,我也希望如果我试图从终端向程序发送一个信号(kill -ALRM'pid'),那个信号会被忽略。这就是为什么我使用变量k:如果我从终端发送信号,k将不同于0(因为来自警报(10)的10个secons没有完全发生),所以信号将被忽略(信号(SIGALRM,SIG_IGN ))。

这就是我所理解的信号的使用,开始意识到我知道几乎为零

对不起,所有发送的潜在歧义

+4

k未初始化,可能不等于零。 – 2014-09-28 11:57:43

+1

未初始化的'k'上的'if'分支有什么意义?那和'signal'有关呢? – mafso 2014-09-28 12:02:14

+0

如果我理解正确,如果全部时间已经转换,则alarm()返回0,否则(当终端发生时)返回剩余时间量。我尝试初始化k = 1,但它也没有工作。 – Ruben 2014-09-28 12:04:12

回答

1

您可以通过alarm()发送的信号区分开来,并且信号通过kill在终端,通过注册您的信号处理程序与sigaction()。这将允许您编写一个信号处理程序,获取更多信息,特别是接受指向struct siginfo_t的指针,该指针包含足够的信息以确定信号来自哪里。

下面是一个例子:

#define _POSIX_C_SOURCE 200809L 

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <signal.h> 

sig_atomic_t s = 0; 

void handler(int signum, siginfo_t * si, void * ucon) { 
    switch (si->si_code) { 
     case SI_USER: 
      printf("Ignoring signal from user, s is %lu...\n", 
        (unsigned long) s); 
      break; 

     case SI_KERNEL: 
      s += 10; 
      printf("Processing signal from alarm(), s is %lu...\n", 
        (unsigned long) s); 
      break; 

     default: 
      printf("Ignoring signal from unknown source, s is %lu...\n", 
        (unsigned long) s); 
      break; 
    } 
} 


int main(void) { 

    /* Set up struct sigaction */ 

    struct sigaction sa; 
    sa.sa_handler = NULL; 
    sa.sa_sigaction = handler; 
    sa.sa_flags = SA_SIGINFO; 
    sigemptyset(&sa.sa_mask); 

    /* Register signal handler */ 

    if (sigaction(SIGALRM, &sa, NULL) == -1) { 
     perror("Couldn't register signal handler."); 
     return EXIT_FAILURE; 
    } 

    /* Go into alarm loop */ 

    while (s < 100) { 
     alarm(10); 
     pause(); 
    } 

    return 0; 
} 

请注意,我们通常不会在信号处理程序进行IO,所以这是仅用于演示目的。

示例输出:

[email protected]:~/src/sandbox$ ./alarm & 
[1] 2042 
[email protected]:~/src/sandbox$ ps | grep alarm 
2042 pts/0 00:00:00 alarm 
[email protected]:~/src/sandbox$ Processing signal from alarm(), s is 10... 
kill -ALRM 2042 
Ignoring signal from user, s is 10... 
[email protected]:~/src/sandbox$ Processing signal from alarm(), s is 20... 
kill -ALRM 2042 
Ignoring signal from user, s is 20... 
[email protected]:~/src/sandbox$ kill -ALRM 2042 
Ignoring signal from user, s is 20... 
[email protected]:~/src/sandbox$ kill -9 2042 
[email protected]:~/src/sandbox$ 
[1]+ Killed     ./alarm 
[email protected]:~/src/sandbox$ 

在这种情况下,通过alarm()发送的信号具有的SI_KERNELsi_code,而(在终端,同样的事情或kill命令)经由kill()发送的那些具有si_codeSI_USER,所以你可以告诉源。

很明显,您必须首先接收信号才能找到此信息,所以您实际上无法根据来源忽略它。一般情况下,这很好,但在你的情况下,它会导致问题,因为你使用pause()来分隔你的电话到alarm(),pause()将返回任何信号被捕获。因此,虽然您事实上可以忽略处理器中的kill()信号,但它仍会在十秒钟内触发另一个警报,因为这就是您的主循环的工作原理。您仍然会收到alarm()发送的十个信号,您将只能处理这十个信号,但其时间将受终端使用kill的影响。

明显的解决方案当然不是使用pause()来达到这个目的。如果你想使用这样的定时器,那么只需使用一个普通的POSIX定时器,你就不会遇到这个问题。你可以用一种替代方法来凑合它,但是当你只需要使用一个普通的POSIX定时器的时候,这样做毫无意义。

+1

你不应该在信号处理程序中调用printf()。 (OP没有犯此错误) – wildplasser 2014-09-28 21:34:31

+1

@wildplasser:有没有关于“请注意,我们在信号处理程序中不能正常执行IO,所以这仅用于演示目的”,这是不明确的? – 2014-09-28 21:35:23

+0

不,它仍然是错误的。即使为了演示目的。未来的读者可能会重复使用您的代码段(因为它*看起来很实体),而忽略文本。 – wildplasser 2014-09-28 21:36:22