組込みからPC、サーバ、スマホまで、実験的に開発中。
clock_nanosleepを使ったタイマ処理
タイマを使って定期的にサーバにPOSTするプログラムを組んだ際、途中でタイマが止まってしまう不具合が発生しました。
これは定期実行のために使っていたsetitimerの設定がlibcurlのタイムアウト処理で上書きされてしまうのが原因でした。
setitimerはプロセスごとに固有なため、lubcurlを使うならsetitimerは使えません。というわけで、clock_nanosleepを使ってやってみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
void periodic_invoke (__time_t interval, void(*func)(void), bool* term) { // パラメータチェック assert((func != NULL) && "pointer func is NULL."); assert((term != NULL) && "pointer terminator is NULL."); // sleep_toに現在の時間をセット struct timespec sleep_to; clock_gettime(CLOCK_MONOTONIC, &sleep_to); struct tm* tm; // *termがtrueになったら終了 while (*term == false) { // スリープ終了時間をinterval秒後にセット sleep_to . tv_sec += interval; // 関数を実行 func(); // sleep_toの時間になるまでまでスリープ // シグナルでスリープを途中で抜けた場合に備えてループで回す struct timespec now; // 現在の時間 while (1) { // *termがtrueになっていればスリープ終了 if (*term == true) { break; } // sleep_toまでスリープ clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &sleep_to, NULL); // sleep_toと現在の時間を比較 clock_gettime(CLOCK_MONOTONIC, &now); // 秒がタイマ設定を超えていればスリープ終了 if (now . tv_sec > sleep_to . tv_sec) { break; // 秒が同じでナノ秒がタイマ設定以上ならスリープ終了 } else if (now . tv_sec == sleep_to . tv_sec && now . tv_nsec >= sleep_to . tv_nsec) { break; } } } } |
interval秒ごとにfunc関数を呼び出します。
別スレッドやシグナルハンドラで*termがtrueにセットされるとループを抜けます。