8.ボタンの制御
TOP
10.セマフォについて

9.タスクについて

一言で言うとタスクとはプログラムの実行単位です。ここまではタスクに関して特に意識してプログラムしていなかったことと思います。それは、タスクが1つだけ(シングルタスクといいます)でそれを順序通りこなしていくようなプログラムしか組んでなかったからです。しかし、複数の処理を同時に実行させたいとき、シングルタスクではできません。そういったときに、マルチタスクが必要となってきます。brickOSはマルチタスク機能を提供しています。マルチタスクとは複数のタスク(仕事)切り替えながら処理することでほぼ同時に処理していく仕組みのことをいいます。この項ではタスク管理の簡単な説明とマルチタスクプログラミングの仕方について説明します。

1.まずはタスクを知る

 まず、マルチタスクプログラムを組んでみて、その動作を見てましょう。
次のプログラムを作成してください。ここでは作成ファイル名をtask1.cとします。
作成したプログラムtask1.c
#include<conio.h>
#include<unistd.h> // execi function is included

tid_t t_task1,t_task2,t_task3;

int task1(){ // task1 function
	int roop;
	for(roop=0;roop<500;roop++){
		cputs("task1");
	}
	return 0;
}


int task2(){ // task2 fanction
	int roop;
	for(roop=0;roop<500;roop++){
		cputs("task2");
	}
	return 0;
}

int task3(){// task3 fanction
	int roop;
	for(roop=0;roop<500;roop++){
		cputs("task3");
	}
	return 0;
}

int main(int argc, char **argv) {
	t_task1=execi(&task1,0,NULL,10,DEFAULT_STACK_SIZE); // make task1
	t_task2=execi(&task2,0,NULL,50,DEFAULT_STACK_SIZE); // make task2
	t_task3=execi(&task3,0,NULL,100,DEFAULT_STACK_SIZE); // make task3
	return 0;
}
 それではタスクの説明に入りましょう。このプログラムではタスクは3つあります。task1,2,3はそれぞれLCDに『task1,2,3』と500回表示するタスクです。このタスクを生成するAPIが『execi()』です。これはtid_t型(プロセスID)でプロセス生成に成功したときプロセスID番号を返し、

プログラムを起動した時点で、execi()で生成したタスク以外に、main 関数の実行にあたって、優先度 10 の main タスクが生成されています。この例では、main はタスク生成を生成するだけでその実行を終えるため、上記の様な場合にアイドルタスクへと処理が移ります。

3.wati_eventの意味

いままで『wait_event()』関数も頻繁に使ってきました。この関数は引数として指定したイベント発生まで、そのタスクを眠らせるという動作をします。このとき、タスクはどうなっているのか見てましょう。 次のプログラムを作成してください。ここでは作成ファイル名をtask3.cとします。
作成したプログラムtask3.c
#include<conio.h>
#include<dsensor.h>
#include<unistd.h> // wait_event function is included

wakeup_t sensor_press_wakeup(wakeup_t data); // wakeup_function
tid_t t_task1,t_task2;

int task1(){ // task1 function
	cputs("task1");
	wait_event(&sensor_press_wakeup,0);
	cputs("tson");
	return 0;
}


int task2(){ // task2 fanction
	sleep(2);
	cputs("task2");
	return 0;
}

int main(int argc, char **argv) {
	t_task1=execi(&task1,0,NULL,50,DEFAULT_STACK_SIZE); // make task1
	t_task2=execi(&task2,0,NULL,10,DEFAULT_STACK_SIZE); // make task2
	return 0;
}

wakeup_t sensor_press_wakeup(wakeup_t data) { // wakeup_function
	return SENSOR_1<0xf000;
}

今回はtask1でwait_event()関数を,task2でsleep()関数を使っています。このときのタスクの状態を示します。ここでは十分時間がたった後(task2終了後)タッチセンサーがONになったときを想定しています。

実行状態のタスクがwait_eventで実行権を放棄すると、タイムスライスが余っていても直ちにタスクスケジューラが起動されて、実行するタスクの選定が行われます。ここではtask1(優先度50)が実行権を放棄したところでtask2(優先度10)が起動しています。これにより、LCDは『task1』⇒『sleep』となるわけです。ここまでの動作はsleep関数と同様です。では、wait_event()関数ではどのタイミングで実行権を取り戻すのでしょうか。それは、wait_event()で指定されたウェイクアップ関数(ここでは『sensor_press_wakeup()』)の戻り値が"NoneNull"のときに実行権を取り戻します。ただし、ウェイクアップ関数の評価は常に行われているわけではなく、タイムスライス毎に行われます。よってタイムスライスの間にwait_event()から復帰することはありません。

4.課題

光センサでライントレースを行い、途中で障害物に衝突したら停止または反転す るプログラムを作成し、その動作を確認せよ。なお、タッチセンサと光センサはともに前面に取りつけること。
ヒント:タッチセンタと光センサの入力を wait_event するタスクをそれぞれ生成する。

5.まとめ

 この章ではタスクについて学習しました。マルチタスクに動かすことにより今までできなかった動作をすることが可能になります。この章は難しかったと思いますが、重要な概念ですので、説明を読むなり、自分でプログラムを組んでみるなりしてよく理解しておいてください。また、複数のタスク間の同期についてはセマフォの項で説明します。
8.ボタンの制御
TOP
10.セマフォについて