0

GPSモジュールからデータを取得して処理する、Raspberry-Pi(Linux)で実行されるプログラムを開発しています。

現在、プログラムは GPS データを取得して処理するループを中心にしていwhile(1)ます (データは 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 に答える