Использование сигналов в C, как остановить и продолжить программу, когда таймер заканчивается
Я разрабатываю программу, которая работает на Raspberry-Pi (linux), которая получает данные от модулей GPS и обрабатывает их.
Прямо сейчас, программа сосредоточена вокруг while(1)
Цикл, который принимает данные GPS и делает что-то с ними (данные передаются с частотой модуля GPS).
Однако я знаю while(1)
не очень энергоэффективное решение, (этот RPi будет сидеть на дроне позже).
Я хотел бы установить таймер, и только когда таймер закончится, программа будет принимать данные GPS. В идеале программа должна быть полностью остановлена, пока не закончится таймер, чтобы процессор не тратил на это время и энергию.
Как я могу сделать вышеупомянутое, если
SIGSTOP
сигнал не допускается вsigaction()
звонки?
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.
}
}
1 ответ
В вашем цикле просто позвоните 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()
с маской сигнала, которая его разблокирует, безопасно знать, что разблокировка и ожидание сигнала будут атомарной операцией. Вот пример такого подхода:
#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$
Проверка ошибок была опущена для краткости в вышеприведенных примерах, но ваш код, конечно, должен включать ее для каждого системного вызова.