- マルチタスクとは
- 今まで習ってきたC言語のプログラムでは、複数の処理が並列に動作をしていなかった。マルチタスクでは処理をタスクという小さな実行単位に分けて並列に処理をする。つまり、タスクは並列実行の単位である。
なお、LEGO EV3は1CPUシングルコアなので、複数の処理を同時に処理できいない。高速にタスクを切り替えて疑似的に並列に実行しているように見える処理を行う。
また、タスクに優先度をつけることができ、他のタスクより優先的に処理をすることもできる。
- 今まで習ってきたC言語のプログラムでは、複数の処理が並列に動作をしていなかった。マルチタスクでは処理をタスクという小さな実行単位に分けて並列に処理をする。つまり、タスクは並列実行の単位である。
- マルチタスクの仕組み
CRE_TSK: タスク生成API
DOMAIN(TDOM_APP) { CRE_TSK(BALANCE_TASK, { TA_NULL, 0, balance_task, TMIN_APP_TPRI, STACK_SIZE, NULL }); CRE_TSK(MAIN_TASK, { TA_ACT, 0, main_task, TMIN_APP_TPRI + 1, STACK_SIZE, NULL }); CRE_TSK(IDLE_TASK, { TA_NULL, 0, idle_task, TMIN_APP_TPRI + 2, STACK_SIZE, NULL }); }
CRE_TSKの各パラメータの意味は、以下の通りです。
- 【第1パラメータ】タスクのID。大文字で書く。
- 【第2パラメータ】タスクの属性。
- TA_ACTを指定すると、アプリケーション起動時にタスクを実行可能状態に遷移させる。
- TA_NULLを指定すると、アプリケーション起動時には休止状態である。途中から起動したいタスクで設定する。
- 【第3パラメータ】タスクに渡される値(拡張情報)。本演習では0を入れる。
- 【第4パラメータ】周期的に実行される関数
- 【第5パラメータ】TMIN_APP_TPRI:タスクの起動時優先度。EV3RTの場合、TMIN_APP_TPRIは、タスクに指定できる最高優先度(値は最小値)を示す。
- 数値を小さくすると優先度が高くなり、大きくすると優先度が下がる。
- したがって、この例では、BALANCE_TASKの優先度が最も高く, IDLE_TASKの優先度が最も低く設定されている。
- 【第6パラメータ】タスクのスタック領域のサイズ。本演習ではSTACK_SIZEのままで問題ない。
- 【第7パラメータ】タスクのスタック領域の先頭番地。本演習ではNULLで問題ない。
tslp_tsk: 起床待ちAPI
tslp_tsk 起床待ち(タイムアウト付き)
【C言語API】
ER ercd = tslp_tsk(TMO tmout)
【パラメータ】
TMO tmout タイムアウト時間(tslp_tskの場合)
【リターンパラメータ】
ER ercd 正常終了(E_OK)またはエラーコード
【エラーコード】
E_CTX コンテキストエラー ・ディスパッチ保留状態からの呼出し【NGKI1254】 E_NOSPT 未サポート機能 ・制約タスクからの呼出し【NGKI1255】 E_PAR パラメータエラー ・tmoutが無効(tslp_tskの場合)【NGKI1256】 E_TMOUT ポーリング失敗またはタイムアウト(slp_tskを除く)【NGKI1
act_tsk: タスク起動API
act_tsk タスクの起動〔T〕
【C言語API】
ER ercd = act_tsk(ID tskid) ER ercd = iact_tsk(ID tskid)
【パラメータ】
ID tskid 対象タスクのID番号
【リターンパラメータ】
ER ercd 正常終了(E_OK)またはエラーコード
【エラーコード】
E_CTX コンテキストエラー ・非タスクコンテキストからの呼出し(act_tskの場合)【NGKI1112】 ・タスクコンテキストからの呼出し(iact_tskの場合)【NGKI1113】 ・CPUロック状態からの呼出し【NGKI1114】 E_ID 不正ID番号 ・tskidが有効範囲外【NGKI1115】 E_NOEXS オブジェクト未登録 ・対象タスクが未登録〔D〕【NGKI1116】 E_OACV オブジェクトアクセス違反 ・対象タスクに対する通常操作1が許可されていない(act_tsk の場合)〔P〕【NGKI1117】 E_QOVR キューイングオーバフロー ・条件については機能の項を参照
【機能】
tskidで指定したタスク(対象タスク)に対して起動要求を行う.具体的な振舞 いは以下の通り.
対象タスクが休止状態である場合には,対象タスクに対してタスク起動時に行 うべき初期化処理が行われ,対象タスクは実行できる状態になる.
対象タスクが休止状態でない場合には,対象タスクの起動要求キューイング数 に1が加えられる.起動要求キューイング数に1を加えると TMAX_ACTCNTを超える場合には,E_QOVRエラーとなる.
act_tskにおいてtskidにTSK_SELF(=0)を指定すると,自タスクが対象タスク となる.
-
- マルチタスクの場合、一つのタスクにずっとプロセッサが割り当てられているわけではない。そのため、タスクは次のような状態を持つ。
- 実行できる状態(runnable)
- 実行状態(running)
- 実行可能状態(ready)
- 休止状態(dormant)
- 広義の待ち状態(blocked)
- (狭義の)待ち状態(waiting):… タスクが自ら実行を止めている状態
- 強制待ち状態(suspended):… タスクが他のタスクによって実行を止められた状態
- 二重待ち状態(waiting-suspended)
- 実行できる状態(runnable)
- 専門用語
- スケジューリング:どの時間にどのタスクを実行するか決めること
- ディスパッチ:プロセッサが処理するタスクを切り替えること
- プリエンプト:実行中のタスクを一時的に中断すること
- マルチタスクの場合、一つのタスクにずっとプロセッサが割り当てられているわけではない。そのため、タスクは次のような状態を持つ。
-
- サンプルプログラム
- ソースファイル:/multi-task1/app.c、設定ファイル:/multi-task1/app.cfg
プログラム起動後、MAIN_TASKがSUB_TASKを起動する。MAIN_TASKのカウント数がLCDに表示されてから、SUB_TASKのカウント数がLCDに表示される。 - ソースファイル:/multi-task2/app.c、設定ファイル:/multi-task2/app.cfg
プログラム起動後、MAIN_TASKがSUB_TASKを起動する。MAIN_TASK、 SUB_TASKのどちらも、カウント数をLCDに同時に表示する。
- 演習1
- サンプルプログラムmulti-task1を実行してください。MAIN TASK = 0と表示されてからカウントアップし、MAIN terminated!と表示されてから、SUB TASK = 0が表示されてからカウントアップし、SUB terminated!と表示されます。
これを先にSUB TASK = 0から実行し、SUB terminated!と表示した後に、MAIN TASK = 0、カウントアップし、MAIN terminated!と表示するように変えてください。
ヒント:app.cfgで設定されているSUB_TASKの優先度を変えてみよう! - サンプルプログラムmulti-task1, multi-task2の動作を確認してください。multi-task1は並列動作していませんが、multi-task2は並列動作しています。2つのサンプルプログラムを見比べて 動作の違いの理由を考えて説明してください。
ヒント:multi_task2はtslp_tskが呼び出されているのでMAIN_TASKが待ち状態になり、SUB_TASKにCPUが割り当てられて処理されます。multi_task1のMAIN_TASKはどのような状態ですか? - サンプルプログラム multi-task2のsub_taskとmain_taskをもとに、以下のプログラムを作成しよう。
『3つのタスク(MAIN_TASK、SUB_TASK1、SUB_TASK2)で、各タスクがカウント数をLCDに表示する。』なお、multi-task2のmain_taskをベースにmain_taskを作成してください。
ヒント:新たにsub_task2を作成した場合は、app.hに以下のプロトタイプ宣言を加えてください。なお、プロトタイプ宣言は関数の宣言のことです。
extern void sub_task2(intptr_t exinf);
終わり