C语言 C: SIGALRM - 每秒显示消息的警报
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21542077/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C: SIGALRM - alarm to display message every second
提问by vivav
So I'm trying to call an alarm to display a message "still working.." every second. I included signal.h.
因此,我正在尝试拨打警报以每秒显示一条消息“仍在工作......”。我包括了signal.h。
Outside of my main I have my function: (I never declare/define s for int s)
在我的 main 之外,我有我的函数:(我从不为 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);
}
Then, in my main
然后,在我的主要
while(1)
{
signal(SIGALRM, display_message);
alarm(1); //Alarm signal every second.
That's in there as soon as the loop begins. But the program never outputs the 'still working...' message. What am I doing incorrectly? Thank you, ver much appreciated.
循环一开始就在那里。但程序永远不会输出“仍在工作...”消息。我做错了什么?谢谢,非常感谢。
回答by Potatoswatter
Signal handlers are not supposed to contain "business logic" or make library calls such as printf. See C11 §7.1.4/4 and its footnote:
信号处理程序不应包含“业务逻辑”或进行诸如printf. 参见 C11 §7.1.4/4 及其脚注:
Thus, a signal handler cannot, in general, call standard library functions.
因此,信号处理程序通常不能调用标准库函数。
All the signal handler should do is set a flag to be acted upon by non-interrupt code. This program runs correctly and does not risk crashing, even if some I/O other functionality were added:
信号处理程序应该做的就是设置一个标志以供非中断代码执行。即使添加了一些 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 );
}
}
}
Note, though, that spin loops are an awful way to program. This example uses 100% CPU power because it never sleeps. Furthermore alarmdoes not appear to be defined by the C standard although POSIX marks it as such and I recall it was part of K&R. So in terms of portability, you would be just as well off with another POSIX facility.
但是请注意,自旋循环是一种糟糕的编程方式。此示例使用 100% CPU 功率,因为它从不休眠。此外alarm,虽然 POSIX 将其标记为 C 标准,但它似乎并未由 C 标准定义,我记得它是 K&R 的一部分。因此,在可移植性方面,您可以使用另一个 POSIX 工具。
回答by ooga
Move the calls to signaland alarmto just before your loop. Calling alarmover and over at high speed keeps resetting the alarm to be in one second from that point, so you never reach the end of that second!
移动呼叫signal和alarm只是你的循环之前。alarm高速呼唤一遍又一遍,不断将闹钟重置为从那一刻起的一秒内,因此您永远不会到达那一秒的尽头!
For example:
例如:
#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;
}
回答by mbornet
Do not call alarm()twice, just call it once in main()to initiate the callback, then once in display_message().
Try this code on Linux (Debian 7.8) :
不要调用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();
}
}
The result will be the following one :
结果将是以下之一:
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...
回答by Alexis Wilke
The alarm()call is for a one off signal.
该alarm()呼叫是针对一次性信号的。
To repeat an alarm, you have to call alarm()again each time the signal occurs.
要重复警报,您必须在alarm()每次信号出现时再次呼叫。
However, the correct way to wait for the next SIGALRMis to use the pause()function. Something the others have not mentioned (instead they have tight loops, ugly!)
但是,等待下一个的正确方法SIGALRM是使用该pause()功能。其他人没有提到的东西(相反,他们有紧密的循环,丑陋!)
That being said, what you are trying to do would be much easier with a simple sleep()call as in:
话虽如此,通过简单的sleep()调用,您尝试做的事情会容易得多,如下所示:
// print a message every second (simplified version)
for(;;)
{
printf("My Message\n");
sleep(1);
}
Note: The sleep()function is actually implemented using the same timer as the alarm()and it is clearly mentioned that you should not mix both functions in the same code.
注意:该sleep()函数实际上是使用与 相同的计时器实现的alarm(),并且明确提到不应在同一代码中混合使用这两个函数。
sleep(3)may be implemented usingSIGALRM; mixing calls toalarm()andsleep(3)is a bad idea.
sleep(3)可以使用实现SIGALRM;混合调用alarm()和sleep(3)是一个坏主意。
(From Linux man alarm)
(来自 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;
}
You can create variations. For example, if you want the first message to happen after 1 second instead of immediately, move the pause()before the printf().
您可以创建变体。例如,如果你想在1秒钟后,而不是立即发生的第一条消息,移动pause()之前printf()。
The "other work" comment supposes that your other work does not take more than 1 second.
“其他工作”注释假设您的其他工作不超过 1 秒。
It is possible to get the alarm signal on a specific thread if work is required in parallel, however, this can be complicated if any other timers are required (i.e. you can't easily share the alarm()timer with other functions.)
如果需要并行工作,可以在特定线程上获取警报信号,但是,如果需要任何其他计时器,这可能会很复杂(即您不能轻松地alarm()与其他功能共享计时器。)
P.S. as mentioned by others, doing your printf()inside the signal handler is not a good idea at all.
PS 正如其他人所提到的,printf()在信号处理程序内部进行处理根本不是一个好主意。
There is another version where the alarm()is reset inside main()and the first message appears after one second and the loop runs for 60 seconds (1 minute):
还有另一个版本,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;
}
Note that with this method, the time when the message will be printed is going to be skewed. The time to print your message is added to the clock before you restart the alarm... so it is always going to be a little over 1 second between each call. The other loop is better in that respect but it still is skewed. For a perfect(much better) timer, the poll()function is much better as you can specify when to wake up next. poll()can be used just and only with a timer. My Snap libraryuses that capability (look for the run()function, near the bottom of the file.)
请注意,使用此方法,打印消息的时间将出现偏差。在您重新启动闹钟之前,打印消息的时间会添加到时钟中……因此每次通话之间总是会有 1 秒多一点的时间。另一个循环在这方面更好,但它仍然存在偏差。对于完美(更好)的计时器,该poll()功能要好得多,因为您可以指定下一次醒来的时间。poll()只能与计时器一起使用。我的Snap 库使用该功能(run()在文件底部附近查找该功能。)
There are also several Alarm and other signals code samplesfrom the US Naval Academy.
还有几个来自美国海军学院的警报和其他信号代码示例。
回答by Duck
oogais correct that you keep reloading the alarm so that it will never go off. This works. I just put a sleepin here so you don't keep stepping on yourself in the loop but you might want to substitute something more useful depending on where you are headed with this.
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);
}

