簡體   English   中英

使用C中的信號,如何在計時器結束時停止和繼續執行程序

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM