所以我试图通过报警来显示每秒钟“仍在工作......”的消息。 我包括了signal.h。
在我的主要之外,我有我的功能:(我从不为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.
循环开始时就在那里。但该程序从未输出“仍在工作......”的消息。我做错了什么?谢谢,非常感谢。
答案 0 :(得分:12)
信号处理程序不应包含“业务逻辑”或进行库调用,例如printf
。见C11§7.1.4/ 4及其脚注:
因此,信号处理程序通常不能调用标准库函数。
所有信号处理程序应该设置一个标志,由非中断代码执行。即使添加了一些I / O其他功能,该程序也能正确运行并且不会有崩溃的风险:
#include <signal.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
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&amp; R的一部分。因此,就可移植性而言,您可以使用另一个POSIX工具。
答案 1 :(得分:4)
将调用移至signal
和alarm
,直到您的循环之前。高速反复呼叫alarm
会使警报从此时开始重置一秒钟,因此您永远不会达到那一秒的结束!
例如:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
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;
}
答案 2 :(得分:1)
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秒后发生而不是立即发生,请在pause()
之前移动printf()
。
&#34;其他工作&#34;评论假设您的其他工作不会超过1秒。
如果需要并行工作,可以在特定线程上获取警报信号,但是,如果需要任何其他计时器,这可能会很复杂(即,您无法轻松共享alarm()
具有其他功能的计时器。)
P.S。正如其他人所提到的,在信号处理程序中执行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 library使用该功能(在文件底部附近查找run()
函数。)
美国海军学院还有几个Alarm and other signals code samples。
答案 3 :(得分:1)
请勿两次调用alarm()
,只需在main()
中调用一次以启动回调,然后在display_message()
中调用一次即可。
在Linux(Debian 7.8)上尝试以下代码:
#include <stdio.h>
#include <signal.h>
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);
}
int main()
{
signal(SIGALRM, display_message);
alarm(1); // Initial timeout setting
while (1)
{
pause();
}
}
结果将是以下结果:
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
答案 4 :(得分:-1)
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);
}