7

Cを使用してx秒ごとにいくつかの関数を実行するタイマーの例はありますか?

動作するコードの例をいただければ幸いです。

4

4 に答える 4

15

新しいスレッドを生成できます。

void *threadproc(void *arg)
{
    while(!done)
    {
        sleep(delay_in_seconds);
        call_function();
    }
    return 0;
}
...
pthread_t tid;
pthread_create(&tid, NULL, &threadproc, NULL);

alarm(2)または、またはでアラームを設定できますsetitimer(2)

void on_alarm(int signum)
{
    call_function();
    if(!done)
        alarm(delay_in_seconds);  // Reschedule alarm
}
...
// Setup on_alarm as a signal handler for the SIGALRM signal
struct sigaction act;
act.sa_handler = &on_alarm;
act.sa_mask = 0;
act.sa_flags = SA_RESTART;  // Restart interrupted system calls
sigaction(SIGALRM, &act, NULL);

alarm(delay_in_seconds);  // Setup initial alarm

もちろん、これらのメソッドはどちらも、定期的に呼び出す関数がスレッドセーフである必要があるという問題があります。

シグナルメソッドは、非同期セーフでなければならないため、特に危険です。これは、実行が非常に困難です。メモリを割り当てる可能性がprintfあるため、安全ではないような単純なものでも、への呼び出しが中断された場合は、次の理由で問題が発生します。再入可能ではありません。したがって、シグナルハンドラーにフラグを設定するだけで、後で他の関数によってチェックされ、スレッドバージョンと同じ場所に戻される場合を除いて、シグナルメソッドはお勧めしません。printfSIGALRMmallocmalloc

于 2012-12-17T23:50:55.173 に答える
6

インターバルタイマーとシグナルを使用してこれを行うためのさまざまなレガシー方法がありますが、2つの最新のアプローチを紹介します。

POSIXタイマーの使用

POSIXtimer_create関数は、タイマーの期限が切れたときに1回限りまたは定期的な通知を配信するように構成できるタイマーを作成します。タイマーを作成するときに、シグナルまたは新しいスレッドのいずれかで配信をリクエストできます。シグナルを正しく使用することは複雑であるため(シグナルハンドラーから実行できることと実行できないことについての厳格なルールがあり、不運になるまでルールを破ることはしばしば「機能するように見える」)、スレッドベースの配信を使用することをお勧めします。

スレッドで自分のタイマーを回転させる

これは、思ったほど簡単です。スリープ状態になり、必要な時間が経過するたびに必要な処理を実行する新しいスレッドを作成します。

于 2012-12-17T23:54:12.853 に答える
1

スレッドが必要ない場合は、sleep

int time = 10;
printf("time: %ds\n", time);
int i = 0;
while(i<time) {

        printf("doing stuff in duration %d\n", i);
        //stuff();
        sleep(1);
        i++;
}

作業は1秒ごとに開始されるため、この期間内に実行できることを願っています。そうでない場合は、リソースを処理する必要があります。

于 2020-09-30T08:32:10.357 に答える
0

IMOの場合、この場合、次gettimeofday()のようなアルゴリズムを利用できます。while(1)現在の時刻とlast_execution_timeの時間差をカウントするようなアルゴリズムを使用し、差が1秒に達するたびに、last_execution_timeを更新して、1秒ごとに実行されるはずの関数を呼び出します。

#include <stdio.h>
#include <sys/time.h>

#DEFINE DESIRED_INTERVAL 1  //1 second
int get_tv_cur_minus_given(struct timeval *tv, struct timeval *tp_given, int *sign)
{
    struct timeval tp_cur;


    gettimeofday(&tp_cur,NULL);

    tv->tv_sec  = tp_cur.tv_sec - tp_given->tv_sec;
    tv->tv_usec = tp_cur.tv_usec - tp_given->tv_usec;

    if(tv->tv_sec > 0) {
        *sign = 1;
        if(tv->tv_usec < 0) {
            tv->tv_sec--;
            tv->tv_usec = 1000000 + tv->tv_usec;
        }
    }else
    if(tv->tv_sec == 0) {
        if(tv->tv_usec == 0)
            *sign = 0;
        else
        if(tv->tv_usec < 0) {
            *sign = -1;
            tv->tv_usec *= -1;
        }else
            *sign = 1;
    }else {
        *sign = -1;
        if(tv->tv_usec > 0) {
            tv->tv_sec++;
            tv->tv_usec = 1000000 - tv->tv_usec;
        }else
        if(tv->tv_usec < 0)
            tv->tv_usec *= -1;
    return 0;
        }
}

int main()
{
    struct timeval      tv_last_run;
    struct timeval  tv_diff;
    int sign;


    while(true)
    {

     get_tv_cur_minus_given(&tv_diff, &tv_last_run, &sign);

        if(tv_diff.tv_sec > DESIRED_INTERVAL)
        {
            gettimeofday(&tv_last_run,NULL);
            printf("\ncall the func here");
        }
    }

    return 0;
}

メインスレッドから別のスレッドが必要な場合は、main()内の行を関数ポインターに移動し、pthread_create関数に渡します。例:

void *threadproc(void *arg)
{
   while(1)
   {
       //put the same lines as inside main() function in above code snippet. .
   }
}
pthread_create(&tid, NULL, &threadproc, NULL);
于 2018-09-01T18:29:35.010 に答える