[英]Using signals in C, how to stop and continue a program when timer ends
我正在开发一个在Raspberry-Pi(Linux)上运行的程序,该程序从GPS模块获取数据并进行处理。
现在,该程序以while(1)
循环为中心,该循环获取GPS数据并对其进行填充(数据以GPS模块的频率进行流式传输)。
但是,我知道while(1)
并不是一种非常省电的解决方案,(此RPi稍后将坐在无人机上)。
我想设置一个计时器,只有在计时器结束时,程序才会获取GPS数据。 理想情况下,程序将完全停止,直到计时器结束,这样CPU才不会浪费时间/精力。
如果在
sigaction()
调用中不允许SIGSTOP
信号,该怎么办?
void timer_handler(int signum){
/* what can I do to make a program stop and coninue,
so that no CPU cycles are devoted to this program until
the timer is elapsed ? (SIGSTOP is not allowed) */
}
int main(int argc, char** argv){
struct sigaction sigAct;
struct itimerval timer;
sa.sa_handler = &timer_handler;
// SIGALRM is only a place holder here..
sigaction(SIGALRM, &sigAct, NULL);
/* Here would be some timer.it_value, timer.it_interval stuff,
setting it to some arbitrary time */
setitimer(ITIMER_REAL, &timer, NULL);
/* Main program loop here */
while(1){
// process GPS data.
// instead of while(1), I'd like this loop to run only when
// the timer ends.
}
}
在您的循环中,只需调用pause()
。 它会阻塞并仅在收到信号时返回,因此您可以运行代码,再次循环并重复。 您需要一个信号处理程序来阻止SIGALRM
终止程序,但是它不需要执行任何操作,您可以将函数体保留为空。
例如:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
void timer_handler(int signum)
{
(void) signum; /* Avoids warning for unused argument */
}
int main(void)
{
struct sigaction sa;
sa.sa_handler = timer_handler;
sa.sa_mask = 0;
sa.sa_flags = 0;
sigaction(SIGALRM, &sa, NULL);
struct itimerval timer;
timer.it_value.tv_sec = 1;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 1;
timer.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &timer, NULL);
while ( 1 ) {
pause();
printf("Timer expired - get GPS data.\n");
}
return 0;
}
产生输出:
paul@horus:~/src/sandbox$ ./alarm
Timer expired - get GPS data.
Timer expired - get GPS data.
Timer expired - get GPS data.
Timer expired - get GPS data.
Timer expired - get GPS data.
Timer expired - get GPS data.
Timer expired - get GPS data.
Timer expired - get GPS data.
^C
paul@horus:~/src/sandbox$
这是一个很粗糙的解决方案。 如果有可能代码有时需要花费比计时器间隔更长的时间运行,那么事情就变得不可靠,您有时可能会跳过信号。 您可能会或可能不会在乎。 对于更复杂的方法,您可以阻止接收SIGALRM
,然后使用sigsuspend()
屏蔽它的信号掩码调用sigsuspend()
,这是安全的,因为知道取消阻塞和等待信号将是原子操作。 这是该方法的示例:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
void timer_handler(int signum)
{
static const char msg[] = "Handler was called.\n";
write(STDIN_FILENO, msg, sizeof(msg) - 1);
(void) signum;
}
int main(void)
{
struct sigaction sa;
sa.sa_handler = timer_handler;
sa.sa_mask = 0;
sa.sa_flags = 0;
sigaction(SIGALRM, &sa, NULL);
struct itimerval timer;
timer.it_value.tv_sec = 1;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 1;
timer.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &timer, NULL);
sigset_t old_mask, block_mask;
sigemptyset(&block_mask);
sigaddset(&block_mask, SIGALRM);
sigprocmask(SIG_BLOCK, &block_mask, &old_mask);
sleep(3); /* To demonstrate signal handler won't be
called until sigsuspend() is called, timer
is firing every second while we're sleeping */
while ( 1 ) {
sigsuspend(&old_mask);
printf("Timer expired - get GPS data.\n");
}
return 0;
}
输出:
paul@horus:~/src/sandbox$ ./alarm2
Handler was called.
Timer expired - get GPS data.
Handler was called.
Timer expired - get GPS data.
Handler was called.
Timer expired - get GPS data.
Handler was called.
Timer expired - get GPS data.
Handler was called.
Timer expired - get GPS data.
Handler was called.
Timer expired - get GPS data.
^C
paul@horus:~/src/sandbox$
为了简洁起见,在上面的示例中省略了错误检查,但是您的代码当然应该在每个系统调用中都包括它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.