【问题标题】:Problem with signal/alarm in unixunix中的信号/警报问题
【发布时间】:2010-12-12 02:40:30
【问题描述】:

问题一定很简单,但是..我不知道是什么。它应该继续打印“alarm”一段时间,但它只打印一次然后程序就死了:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <signal.h>

void onAlarm();

void setupAlarm() {
 signal(SIGALRM, onAlarm);
 alarm(1);
}

void onAlarm() {
 setupAlarm();
 printf("alarmmmmmmmmmmmmmmmmm\n");
}

void main()
{
 setupAlarm();
 sleep(1000);
}

这里可能有什么问题?取出sleep(1000) 会使程序瞬间死亡(也就是说,甚至没有显示那个“alaaarm”)。

回答

好的,下面的代码可以工作了:

void onAlarm() {
    printf("alarmmmmmmmmmmmmmmmmm\n");
    alarm(1);
    sleep(1);
}

void main()
{
    signal(SIGALRM, onAlarm);
    alarm(1);
    sleep(2);
}

但我仍然对此束手无策,并试图理解为什么我需要这样编写代码。

【问题讨论】:

  • 只是一个说明,以确保您知道这一点。如果在 sleep() 期间您被信号唤醒,则对 sleep() 的调用将返回该睡眠中剩余的秒数。它不会继续等待剩余的时间。
  • 阅读 'alarm' 和 'sleep' 的手册页会告诉你到底发生了什么(而且它们很短——你可以在大约只要花时间阅读它们的全部内容你来撰写这篇文章)

标签: c unix signals alarm


【解决方案1】:

糟糕,我之前的回答完全错误。查看调用 onAlarm() 时会发生什么:

  1. 它重置信号处理程序,

  2. 它会重置警报

  3. 它在取消之前的警报后再次开始等待。

实际上到达您对printf 的调用是什么代码路径?

【讨论】:

  • 我不太明白您所说的“旧的默认信号返回”是什么意思。如果可能的话,你能更明确一点吗?我在 Ubuntu 10.10
  • 没关系,反正那是错的。但是在 BSD UNIX 和 SysV UNIX 中,signal(2) 和相关系统调用的语义是不同的;有些人 (sob) 大到可以记住它的发生。
  • 我还是不明白你想去哪里。重置 sinal 处理程序似乎不是问题。问题是它忽略了原来的睡眠。请参阅我的原始帖子上的编辑。
  • @devoured elysium, alarm != sleep,看我的回答
【解决方案2】:

sleep() 被信号中断,errno 被设置为 EINTR。即在你的第一个闹钟之后,sleep() 返回并且你的程序在到达 main 结束时退出。

请注意,您不应从信号处理程序调用 printf,printf 不是信号异步安全的。

可能还有其他问题,请参阅here

我无法重现您的原始代码不打印任何内容的行为,但如果您想知道发生了什么,只需在 strace 或类似工具下运行您的程序即可。

【讨论】:

  • 完全正确。如果 OP 希望它永远运行,请将 sleep(1000); 替换为 while (1) pause();
【解决方案3】:

好吧,首先,您告诉您的环境在一秒钟后生成一个 SIGALRM,然后在一秒钟后退出。尝试将等待时间增加到两秒。

【讨论】:

  • 我猜你指的是睡眠?在 unix 中睡眠以秒为单位,所以 1000 是 1000 秒。我说对了吗?
  • @devoured:啊,我的错。我已经有一段时间没有使用 C 了。
【解决方案4】:

我不知道你的程序,但这对我有用(代码取自here):

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

void catch_alarm (int sig);
void setupAlarm();

/* This flag controls termination of the main loop. */
volatile sig_atomic_t keep_going = 4;


/* The signal handler just clears the flag and re-enables itself. */
void catch_alarm (int sig) {
    keep_going--;
    printf("Alarm!!\n");

    if (keep_going) {
        setupAlarm();
    }
}

void setupAlarm() {
    alarm(1);
    sleep(1);
}

int main (int argc, char **argv) {
    signal(SIGALRM, catch_alarm);
    setupAlarm();

    return EXIT_SUCCESS;
}

这会打印四个 Alarm! 然后退出。

您可以将sleep(1); 替换为main 中的while (keep_going); 以获得相同的结果。

问题是alarm 不在您程序的进程ID 内执行,因此无论警报信号是否被触发,您的程序都可以结束。但是,sleep 将您的程序进程置于hold n 秒,然后继续。如果没有某种方式来“暂停”进程,或者在等待警报时保持进程活动,它就会在执行完所有必须执行的操作后死掉。即使使用线程,没有sleep()while (...) pthread_join(),进程也不会等待您的警报信号而只是结束(死亡)。因此,在等待信号被触发时,您需要以某种方式保持进程处于活动状态,否则它将无法工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多