我正在编写一个程序,每5秒向自己发送一个信号(警报)。我也希望如果用户键入终端" kill -ALRM PID"被忽略了。如果我理解信号调用,我的程序应该这样做,但是,当我从终端使用该命令时,proram认为它是它的一个警报并且不会忽略它
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次。但是,我还想要,如果我尝试从终端向程序发送信号(杀死-ALRM&#39; pid&#39;)信号无法识别。这就是我使用变量k的原因:如果我从终端发送信号,k将不同于0(因为来自警报(10)的10个secons没有完全发生)所以信号将被忽略(信号(SIGALRM,SIG_IGN) ))。这就是我理解信号使用的方式,开始意识到我几乎一无所知
对于所有潜在的歧义感到抱歉
答案 0 :(得分: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,因此仅用于演示目的。
示例输出:
paul@local:~/src/sandbox$ ./alarm &
[1] 2042
paul@local:~/src/sandbox$ ps | grep alarm
2042 pts/0 00:00:00 alarm
paul@local:~/src/sandbox$ Processing signal from alarm(), s is 10...
kill -ALRM 2042
Ignoring signal from user, s is 10...
paul@local:~/src/sandbox$ Processing signal from alarm(), s is 20...
kill -ALRM 2042
Ignoring signal from user, s is 20...
paul@local:~/src/sandbox$ kill -ALRM 2042
Ignoring signal from user, s is 20...
paul@local:~/src/sandbox$ kill -9 2042
paul@local:~/src/sandbox$
[1]+ Killed ./alarm
paul@local:~/src/sandbox$
在这种情况下,alarm()
发送的信号si_code
为SI_KERNEL
,而kill()
发送的信号(或kill
命令发送的信号为si_code
终端,同样的事情)SI_USER
pause()
,所以你可以告诉来源。
显然,您必须先收到信号才能找到此信息,因此您无法根据来源实际忽略该信息。一般来说这很好,但在你的情况下它会导致问题,因为你使用alarm()
将你的电话分开到pause()
,而kill()
将在任何信号后返回被抓住了。因此,虽然您事实上可以忽略处理程序中的alarm()
信号,但它仍会在十秒钟内触发另一个警报,因为这是您的主循环的工作方式。您仍然可以获得kill
发送的十个信号,并且您只能处理这十个信号,但它们的时间安排将受到终端使用pause()
的影响。
显而易见的解决方案当然是不要将{{1}}用于此目的。如果你想使用这样的计时器,那么只需使用常规POSIX计时器,你就不会遇到这个问题。你可以用另一种方法来解决这个问题,但是只要你使用普通的POSIX计时器就可以做到这一点。