RealTime処理のサンプルプログラム
前回の記事ではDockerコンテナ上でcyclictestを実行しました。
今回は
HOWTO build a simple RT applicationを参考にリアルタイムアプリケーションを作成してみます。
Exampleに載っている内容をsample.cとして保存し,以下のコマンドでコンパイルします。
$ gcc -pthread sample.c
Dockerコンテナを起動して実行してみます。生成されたa.outがあるディレクトリ内で以下を実行します。
$ docker run --rm -it --cpu-rt-runtime=950000 --ulimit rtprio=99 --cap-add=sys_nice -v `pwd`:/home ubuntu
コンテナが起動したら/homeに移動し,./a.out
を実行します。
エラーがあった場合にはエラー箇所が表示されますが,正常に動作した場合は何も表示されません。あまり面白くないですね...
周期実行サンプル
HOWTO build a basic cyclic applicationを参考に以下のようなファイルをsample_cyclic.c
として作成します。
/* * POSIX Real Time Example * using a single pthread as RT thread */ #include <limits.h> #include <pthread.h> #include <sched.h> #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <time.h> struct period_info { struct timespec next_period; long period_ns; }; static void inc_period(struct period_info *pinfo) { pinfo->next_period.tv_nsec += pinfo->period_ns; while (pinfo->next_period.tv_nsec >= 1000000000) { /* timespec nsec overflow */ pinfo->next_period.tv_sec++; pinfo->next_period.tv_nsec -= 1000000000; } } static void periodic_task_init(struct period_info *pinfo) { /* for simplicity, hardcoding a 1ms period */ pinfo->period_ns = 1000000; clock_gettime(CLOCK_MONOTONIC, &(pinfo->next_period)); } static void do_rt_task() { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); printf("time: %10ld.%09ld\n", ts.tv_sec, ts.tv_nsec); /* Do RT stuff here. */ } static void wait_rest_of_period(struct period_info *pinfo) { inc_period(pinfo); /* for simplicity, ignoring possibilities of signal wakes */ clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &pinfo->next_period, NULL); } void *thread_func(void *data) { /* Do RT specific stuff here */ struct period_info pinfo; periodic_task_init(&pinfo); while (1) { do_rt_task(); wait_rest_of_period(&pinfo); } return NULL; } int main(int argc, char* argv[]) { struct sched_param param; pthread_attr_t attr; pthread_t thread; int ret; /* Lock memory */ if(mlockall(MCL_CURRENT|MCL_FUTURE) == -1) { printf("mlockall failed: %m\n"); exit(-2); } /* Initialize pthread attributes (default values) */ ret = pthread_attr_init(&attr); if (ret) { printf("init pthread attributes failed\n"); goto out; } /* Set a specific stack size */ ret = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); if (ret) { printf("pthread setstacksize failed\n"); goto out; } /* Set scheduler policy and priority of pthread */ ret = pthread_attr_setschedpolicy(&attr, SCHED_FIFO); if (ret) { printf("pthread setschedpolicy failed\n"); goto out; } param.sched_priority = 80; ret = pthread_attr_setschedparam(&attr, ¶m); if (ret) { printf("pthread setschedparam failed\n"); goto out; } /* Use scheduling parameters of attr */ ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); if (ret) { printf("pthread setinheritsched failed\n"); goto out; } /* Create a pthread with specified attributes */ ret = pthread_create(&thread, &attr, thread_func, NULL); if (ret) { printf("create pthread failed\n"); goto out; } /* Join the thread and wait until it is done */ ret = pthread_join(thread, NULL); if (ret) printf("join pthread failed: %m\n"); out: return ret; }
最初のsample.cと同様に以下のようにしてコンパイルします。
$ gcc -pthread -o cyclic sample_cyclic.c
Dockerコンテナ上で./cyclic
を実行すると以下のように1msごとに時刻が表示されます。
time: 1580301619.999005823 time: 1580301620.000007537 time: 1580301620.001007728 time: 1580301620.002007485 time: 1580301620.003007308 time: 1580301620.004011275 time: 1580301620.005009829 time: 1580301620.006012556 time: 1580301620.007010412 time: 1580301620.008012001 time: 1580301620.009012342
リアルタイム処理の記述
以上でとりあえずサンプルは動きました。
自分の好きなことを好きな間隔で実行させるには以下の箇所を修正します。
static void periodic_task_init(struct period_info *pinfo) { /* for simplicity, hardcoding a 1ms period */ pinfo->period_ns = 1000000; clock_gettime(CLOCK_MONOTONIC, &(pinfo->next_period)); } static void do_rt_task() { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); printf("time: %10ld.%09ld\n", ts.tv_sec, ts.tv_nsec); /* Do RT stuff here. */ }
periodic_task_init内のpinfo->period_ns
を変更すれば実行周期を変えられます。
do_rt_task()の中には周期ごとに実行したい処理を記述しましょう。
以上で最低限のリアルタイムは実行できるようになります。