PD実践: マルチタスク演習1(マルチタスクの仕組み)

  • マルチタスクとは
    • 今まで習ってきたC言語のプログラムでは、複数の処理が並列に動作をしていなかった。マルチタスクでは処理をタスクという小さな実行単位に分けて並列に処理をする。つまり、タスクは並列実行の単位である。
      なお、LEGO EV3は1CPUシングルコアなので、複数の処理を同時に処理できいない。高速にタスクを切り替えて疑似的に並列に実行しているように見える処理を行う。
      また、タスクに優先度をつけることができ、他のタスクより優先的に処理をすることもできる。
  • マルチタスクの仕組み

 

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)
    • 専門用語
      • スケジューリング:どの時間にどのタスクを実行するか決めること
      • ディスパッチ:プロセッサが処理するタスクを切り替えること
      • プリエンプト:実行中のタスクを一時的に中断すること

 

 

    • サンプルプログラム
  1. ソースファイル:/multi-task1/app.c、設定ファイル:/multi-task1/app.cfg
    プログラム起動後、MAIN_TASKがSUB_TASKを起動する。MAIN_TASKのカウント数がLCDに表示されてから、SUB_TASKのカウント数がLCDに表示される。
  2. ソースファイル:/multi-task2/app.c、設定ファイル:/multi-task2/app.cfg
    プログラム起動後、MAIN_TASKがSUB_TASKを起動する。MAIN_TASK、 SUB_TASKのどちらも、カウント数をLCDに同時に表示する。
  • 演習1
  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の優先度を変えてみよう!
  2. サンプルプログラムmulti-task1, multi-task2の動作を確認してください。multi-task1は並列動作していませんが、multi-task2は並列動作しています。2つのサンプルプログラムを見比べて 動作の違いの理由を考えて説明してください。
    ヒント:multi_task2はtslp_tskが呼び出されているのでMAIN_TASKが待ち状態になり、SUB_TASKにCPUが割り当てられて処理されます。multi_task1のMAIN_TASKはどのような状態ですか?
  3.  サンプルプログラム 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);

終わり

コメント

Folding@home Kanazawa (ID 257261)

みんなのためにおうちで新型コロナウイルスを解析しよう!

タイトルとURLをコピーしました