0

我正在开发一个在 Raspberry-Pi (linux) 上运行的程序,它从 GPS 模块获取数据并对其进行处理。

目前,该程序以一个while(1)循环为中心,该循环获取 GPS 数据并对其进行处理(数据以 GPS 模块的频率流式传输)。

但是,我知道while(1)这不是一个非常省电的解决方案,(这个 RPi 稍后会放在无人机上)。

我想设置一个计时器,只有当计时器结束时,程序才会获取 GPS 数据。理想情况下,程序将完全停止,直到计时器结束,这样 CPU 就不会在其上浪费时间/精力。

如果通话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.
    }

}
4

1 回答 1

2

在您的循环中,只需调用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$

为简洁起见,上述示例中省略了错误检查,但您的代码当然应该在每个系统调用中都包含它。

于 2016-05-01T00:17:13.933 回答