C:SIGALRM – 每秒钟显示消息的警报

所以我试着每秒钟拨打一个警报来显示“仍在工作……”的消息。 我包括了signal.h。

在我的主要之外我有我的function:(我从来没有为int声明/定义s)

void display_message(int s); //Function for alarm set up void display_message(int s) { printf("copyit: Still working...\n" ); alarm(1); //for every second signal(SIGALRM, display_message); } 

然后,在我的主要

 while(1) { signal(SIGALRM, display_message); alarm(1); //Alarm signal every second. 

循环开始时就在那里。 但该程序从未输出“仍在工作……”的消息。 我做错了什么? 谢谢,非常感谢。

信号处理程序不应包含“业务逻辑”或进行诸如printf库调用。 见C11§7.1.4/ 4及其脚注:

因此,信号处理程序通常不能调用标准库函数。

所有信号处理程序应该设置一个标志,由非中断代码作用。 即使添加了一些I / O其他function,该程序也能正确运行并且不会有崩溃的风险:

 #include  #include  #include  #include  volatile sig_atomic_t print_flag = false; void handle_alarm( int sig ) { print_flag = true; } int main() { signal( SIGALRM, handle_alarm ); // Install handler first, alarm( 1 ); // before scheduling it to be called. for (;;) { if ( print_flag ) { printf( "Hello\n" ); print_flag = false; alarm( 1 ); } } } 

但请注意,旋转循环是一种糟糕的编程方式。 此示例使用100%CPU功率,因为​​它从不睡觉。 此外, alarm似乎没有被C标准定义,虽然POSIX标记它,我记得它是K&R的一部分。 因此,就可移植性而言,您可以使用另一个POSIX工具。

将调用和alarm的调用移到循环之前。 高速一次又一次地调用alarm会使警报从该点开始重置一秒钟,因此您永远不会到达那一秒的结束!

例如:

 #include  #include  #include  void display_message(int s) { printf("copyit: Still working...\n" ); alarm(1); //for every second signal(SIGALRM, display_message); } int main(void) { signal(SIGALRM, display_message); alarm(1); int n = 0; while (1) { ++n; } return 0; } 

alarm()调用是一次性信号。

要重复闹钟,每次信号发生时都必须再次呼叫alarm()

但是,等待下一个SIGALRM的正确方法是使用pause()函数。 其他人没有提到的东西(相反,他们有紧密的循环,丑陋!)

话虽如此,通过简单的sleep()调用,您尝试做的事情会更容易:

 // print a message every second (simplified version) for(;;) { printf("My Message\n"); sleep(1); } 

注意: sleep()函数实际上是使用与alarm()相同的计时器实现的,并且明确提到不应该在同一代码中混合使用这两个函数。

sleep(3)可以使用SIGALRM实现; 混合调用alarm()sleep(3)是一个坏主意。

(来自Linux man alarm

 void alarm_handler(int) { alarm(1); // recurring alarm } int main(int argc, char *argv[]) { signal(SIGALRM, alarm_handler); alarm(1); for(;;) { printf("My Message\n"); // ...do other work here if needed... pause(); } // not reached (use Ctrl-C to exit) return 0; } 

您可以创建变体。 例如,如果您希望第一条消息在1秒后发生而不是立即发生,请在printf()之前移动pause() printf()

“其他工作”评论假设您的其他工作不超过1秒。

如果需要并行工作,可以在特定线程上获取报警信号,但是,如果需要任何其他定时器,这可能会很复杂(即,您无法轻松与其他function共享alarm()计时器。)

其他人提到的PS,在信号处理程序中执行printf()根本不是一个好主意。

还有另一个版本,其中alarm()main()内重置,第一条消息在一秒钟后出现,循环运行60秒(1分钟):

 void alarm_handler(int) { } int main(int argc, char *argv[]) { signal(SIGALRM, alarm_handler); for(int seconds(0); seconds < 60; ++seconds) { alarm(1); // ...do other work here if needed... pause(); printf("My Message\n"); } // reached after 1 minute return 0; } 

请注意,使用此方法,将打印消息的时间将会偏斜。 在重新启动警报之前,打印消息的时间会添加到时钟中......因此每次调用之间总是会超过1秒。 另一个循环在这方面更好,但它仍然是倾斜的。 对于完美 (更好)的计时器, poll()函数要好得多,因为您可以指定下次唤醒的时间。 poll()只能用于计时器。 我的Snap库使用该function(在文件底部附近查找run()函数。)

还有来自美国海军学院的几个警报和其他信号代码样本 。

ooga是正确的,你不断重新加载警报,以便它永远不会熄灭。 这很有效。 我只是在这里sleep ,所以你不要继续踩在自己的循环中,但你可能想要替换一些更有用的东西,这取决于你的目标。

 void display_message(int s) { printf("copyit: Still working...\n" ); // alarm(1); //for every second // signal(SIGALRM, display_message); } int main(int argc, char *argv[]) { int ret; while(1) { signal(SIGALRM, display_message); alarm(1); if ((ret = sleep(3)) != 0) { printf("sleep was interrupted by SIGALRM\n"); } } return (0); }