TASK(3C++)

名前
task - C++ タスクライブラリのコルーチン

形式

#include <task.h>

typedef int (*PFIO)(int,object*);
typedef void (*PFV)();
class object {
public:
	// 公開された定数と型
	enum objtype { OBJECT, TIMER, TASK, QHEAD, QTAIL, INTHANDLER };

	// 公開されたコンストラクタ
	object();

	// 公開されたデータメンバー
	object*	o_next;
	static	PFIO error_fct;

	// 公開された仮想関数
	virtual	objtype	o_type();
	virtual	int	pending();
	virtual	void	print(int, int=0);
	// 関数の出力時に引数として使用したフラグをプリント
	#define CHAIN		1
	#define VERBOSE	2
	#define STACK		4

	// 公開されたその他の関数
	void	alert();
	void	forget(task*);
	void	remember(task*);

	// 公開された静的メンバー関数
	static	int task_error(int, object*);
	static	task* this_task();
};
class sched: public object {
public:
	// 公開された定数と型
	enum statetype { IDLE=1, RUNNING=2, TERMINATED=4 };

protected:
	// 限定公開コンストラクタ
	sched();

public:
	// 公開されたデータメンバー
	static	task*	clock_task;
	static	PFV	exit_fct;

	// 公開された仮想関数
	virtual	int	pending();
	virtual	void	print(int, int =0);
	virtual	void	setwho(object*);

	// 公開されたその他の関数
	void	cancel(int);
	int	dont_wait();
	sched*	get_priority_sched();
	int	keep_waiting();
	statetype	rdstate();
	long	rdtime();
	int	result();

	// 公開された静的メンバー関数
	static	long	get_clock();
	static	sched*	get_run_chain();
	static	int	get_exit_status();
	static	void	set_exit_status(int i);
	static	void	setclock(long);
};
class task: public sched {
public:
	// 公開された定数と型
	typedef unsigned char _Uchar;
	enum modetype { DEDICATED=1, SHARED=2 };
	#define DEFAULT_MODE DEDICATED
	#define SIZE 3000

protected:
	// 限定公開コンストラクタ
	task(char* = 0, modetype = DEFAULT_MODE, int = SIZE);

public:
	// 公開されたデータメンバー
	task*	t_next;
	_Uchar*	t_name;

	// 公開された仮想関数
	virtual	objtype	o_type();
	virtual	void	print(int, int =0);
	virtual	void	setwho(object*);

	// 公開されたその他の関数
	void	cancel(int);
	void	delay(int);
	int	preempt();
	void	resultis(int);
	void	sleep(object* =0);
	void	wait(object*);
	int	waitlist(object* ...);
	int	waitvec(object**);
	object*	who_alerted_me();

	// 公開された静的メンバー関数
	static	task*	get_task_chain();
};
class timer: public sched {
public:
	// 公開されたコンストラクタ
	timer(int);

	// 公開された仮想関数
	virtual	objtype	o_type();
	virtual	void	print(int, int =0);
	virtual	void	setwho(object*);

	// 公開されたその他の関数
	void	reset(int);
};

機能説明

「タスク」は、対応するプログラムを実行する 制御スレッドを持つオブジェクトです。 つまり、ユーザータスクはクラス task から派生した型のオブジェクトです。 そのオブジェクトのコンストラクタは、タスクのメインプログラムです。 タスクがコンストラクタの終了後も存続することはありません。

タスクシステムは、 直ちに実行できる操作または待機しなければならない操作、 さらに「動作可能」または「保留中」であるオブジェクトに関して機能します。 タスクが直ちに実行できるサービスを要求するか、 動作可能なオブジェクトを待機する場合、そのタスクは処理を続けます。 必要なサービスが直ちに実行されないか、 操作するオブジェクトが使用可能でない場合、タスクはブロックされます。 動作中のタスクがブロックされると、スケジューラは実行可能な次のタスクを選択し、 そのタスクに制御を与えます。 タスクが先取りされることはありません。 ただし、あるタスクをブロックして、 他のタスクを実行できるようにすることがあります。 制御は、ラウンドロビン形式で処理されます (タスクに優先順位を与えたり、 実行を待機しているタスクのリストの先頭に移動することができます)。 オブジェクトが新しく動作可能になるたびに、 それを待機しているすべてのタスクにそのことが通知され、 通知を受けたタスクが実行可能になります。

各タスクには、次の 3 つの状態があります。

    RUNNING
        現在実行中または実行可能。

    IDLE
        実行不可能。オブジェクトを待機中。

    TERMINATED
        タスクは終了し、再開不可能。 タスクの戻り値を取り出すことができます。

タスクシステムは、クラス object にもとづいています。 このクラスから派生されるすべてのオブジェクトは、 キューに登録したり、タスクに待機させることができます。 仮想メンバー関数 pending() は、オブジェクトが動作可能でない場合にゼロ以外の値を返します。 オブジェクトの各型にこの関数の独自のバージョンを用意することができ、 それにより、オブジェクトが動作可能か保留中かを決定する独自の基準を 持つことができます。 ただし、各型のオブジェクトには、そのような関数を 1 つしか定義できません。

各オブジェクトは、それを待機しているオブジェクトのリストである 「リメンバ・チェーン」を持っています。 タスクが動作可能でないオブジェクトを待機していると、 そのタスクは中断され (IDLE 状態)、オブジェクトのリメンバ・チェーンに 追加されます。 次にオブジェクトが動作可能 (保留中ではない) になると、 メンバー関数 object::alert() によって、 待機している各タスクにそのことが通知されます。 この関数は、これらのタスクの状態を RUNNING 状態に変更し、 スケジューラの「実行チェーン」である、動作可能タスクのリストに戻します。

クラス object の派生クラス sched は、タスクのようなオブジェクトに共通の機能を提供します。 スケジューリング関数はこのクラスに含まれています。 スケジューリング操作はスケジューラとして独立しているのではなく、クラス sched の一部分です。 各タスクは他のタスクとともに動作し、 そのメンバー関数を用いてスケジューリングを行います。 このクラスはインスタンス化できません。 task と timer の基底クラスとしてしか使用できません。

また、クラス sched は、時間の経過をシミュレートする機能も提供します。 シミュレートされた時間の単位は実時間と関係がなくてもかまいません。 シミュレートされたシステムクロックはゼロに初期化されます。 クロックの値は、 sched::setclock() によって一度だけ設定できます。 設定後、クロックは task::delay() の呼び出しが行われた場合にだけ進みます。 このときのパラメタは、遅延を示すシミュレートされた単位時間の数です。 パラメタで指定された時間が経過すると、 delay() は制御を呼び出し側に返します。 delay() を呼び出すことで、クロックは、遅延時間と、 何か物事が発生するようにスケジュールされている、次のシミュレートされた時間の早い方に進みます。 クロックの現在の値は、関数 sched::getclock() によって読み取ることができます。

クラス timer は、単に指定されたシミュレートされた時間だけ遅延させ、終了する、 余分な機能をいっさい持たないタスクです。 timer を待機することができ、その時間が経過するとそれを待機しているすべての タスクに通知されます。 timer は、RUNNING または TERMINATED のどちらかの状態にできますが、 IDLE にすることはできません。

クラス task は sched の派生クラスで、ユーザータスクの基本機能を提供します。 task 型のオブジェクトはインスタンス化できません。 すべてのユーザータスクは、クラス task から直接派生されたものでなければなりません。 すなわち、ユーザータスク型から派生型を作成することはできません。 例を示します。
    task mytask;    // エラー : タスクオブジェクトは作成できない。
    class consumer : public task { ... }    // OK
    class glutton : public consumer { ... }    // エラー : 再度派生できない。
コンストラクタ task は protected 宣言されているため、 最初のエラーはコンパイラによって検出され、報告されます。 3 行目のエラーは検出されませんが、プログラムは動作しません。

タスクは、コンストラクタを終了するだけでは終了できません。 また、関数の戻り値の機能を用いて、タスクから値を返すことはできません。 代わりに、タスクの戻り値は task::resultis() または task::cancel() のどちらかを呼び出すことによって設定しなければなりません。 そうすれば、タスクは TERMINATED 状態になります。 あるタスクの戻り値は、他のタスクから task::result() を呼び出すことで取り出すことができます。 この関数は、問い合わせられたタスクが終了するまで、 呼び出し側タスクを中断します。 タスクは値を返す必要がない場合でも、 resultis() または cancel() を呼び出し、そのタスクが破棄される前に適切に終了されるように しなければなりません。

コンストラクタ task は、名前、モード、スタックサイズの 3 つの引数 (省略可能) を持ちます。

名前は、動的に割り当てられた文字列か ヒープ上の文字列でなければならず、 ある関数に対してローカルな文字配列を指定することはできません。 名前は出力上にだけ現れ、タスク操作には影響を与えません。

モードは、タスクが使用するスタックの種類で、 DEDICATED (デフォルト) または SHARED のどちらかになります。 通常、専用のスタック (DEDICATED) が必要です。 すなわち、タスク独自のスタックとして メモリー領域を確保します。 共有スタック (SHARED) は資源を消費します。 これは、タスクが稼働状態になったり非稼働状態になったりするときに、 独自のスタックを共有領域と保存領域との間でスワップしなければならない 場合があるためです。 何百という小規模なタスクがある場合には、 共有スタック領域が有効になります。

スタックサイズは、 タスクが使用できる最大のスタック領域の量を指定します。 デフォルトは 3000 バイトです。 スタック領域がオーバーフローしたかどうかの確実なテストもなく、 スタックを動的に拡大することもできません。 タスクがスワップインされると、スタックサイズがチェックされ、 このときのオーバーフローは致命的エラーとなります。 タスクの実行中に、関数呼び出しのネストが深いことや、 ローカル変数の記憶領域のサイズが大きなことが原因で スタックがオーバーフローすると、プログラムが異常な動作をしたり、 クラッシュすることがあります。

task からクラスを派生すると、そのコンストラクタは、 すでに存在する他のタスクと同時に動作する新しいタスクとなります。 関数 main() は、システムで最初のタスクを作成するタスクになります。 main() の中でいくつかのタスクが順に起動する場合、 最初のタスクがブロックされ、 main() が新しいタスクを作成するための制御を取り戻すまで、 2 番目のタスクを作成することはできません。 また、それ以降のタスクを作成する場合も同じことが言えます。 したがって、 main() は、そのすべてのタスクを起動した後、 タスクが稼働している間は main() 自身が終了したり、プログラム全体を終了させたりすることがないように、 resultis() または cancel() を呼び出す必要があります。

どのタスクコンストラクタも、それ自身が新しいタスクを作成できます。

  クラス object

クラス object には、1 つのコンストラクタしかありません。 このコンストラクタは引数を持ちません。

object o;
    オブジェクト o を作成します (コンストラクタが限定公開であるため、 これは正しくありません) 。 このオブジェクトはどのリストにも存在しません。

object *p = o.o_next;
    オブジェクトは、一度に 1 つのリスト (実行チェーン、キュー、その他) にしか 存在できません。 リストの次のオブジェクトは、公開データメンバー o_next によって指されます。 次のオブジェクトが存在しない場合、 また、特に現オブジェクトがどのリストにも属さない場合、 このメンバーはゼロになります。

objtype t = p->o_type();
    この仮想関数は、 p が指すオブジェクトの型に対応する型 objtype の列挙定数を返します。

int i = p->pending();
    p が指すオブジェクトが動作可能でなければ、ゼロ以外の値 (真) を返します。 派生クラスでオブジェクトを待機する場合、 この仮想関数の適切な (独自の) バージョンを定義しなければなりません。 クラス object のデフォルトの関数は 常に真 (動作可能でない) を返します。 他の定義済みクラスのそれぞれには、 この関数の独自のバージョンが定義されています。

o.print(how);
    p が指すオブジェクトに関する基本情報を stdout ( cout ではない) に出力します。最初の int 型のパラメタ how で VERBOSE ビットがセットされていれば、 該当するオブジェクトの「リメンバ・チェーン」に含まれている すべてのタスクに関する情報を出力します。 2 番目の引数は内部で使用するためのもので、 デフォルトでゼロに設定されます。 通常、この仮想関数は、関数 print() によって派生クラスから呼び出されます。

o.alert()
    タスク o の「リメンバ・チェーン」を検索し、 各タスクのモードを IDLE から RUNNING に変更して 「実行チェーン」に置きます。 あるタスクが保留中のオブジェクトを待機していると、 そのタスクは IDLE モードにされ、 「実行チェーン」から除外され、そのオブジェクトの「リメンバ・チェーン」に 置かれます。 オブジェクトが保留状態でなくなると、 定義済みクラスによってこの関数が自動的に呼びだされ、 待機中のすべてのオブジェクトが稼働状態になります。

o.forget(p)
    タスク o の「リメンバ・チェーン」から、 p が指すタスクのすべてのインスタンスを削除します。

o.remember(p)
    p が指すタスクを、 タスク o の「リメンバ・チェーン」に追加します。

int user_err_func(int, object*);
    object::error_fct = user_err_func;
    この関数を用いて、ユーザーはエラー回復を制御できます。 ユーザーエラー関数を定義する場合、 その関数はパラメタとして、 「診断」の項で示すエラー番号の 1 つ ( int 型) と、オブジェクトへのポインタを持たなければなりません。 このポインタは、関数 object::task_error() を呼び出したオブジェクト、 または下記のようにエラーを処理するオブジェクトになります。 静的データメンバー object::error_fct は、そのようなユーザーエラー関数を指すように設定できます。 このメンバーが設定されていれば、 task_error() はユーザー関数を呼び出します。 ユーザー関数がゼロを返すと、 task_error() は制御を戻し、 エラーの原因となった操作がおそらく再試行されます。 ユーザー関数がゼロ以外の値を返した場合、 task_error() は exit() を呼び出します。

int i = o.task_error(err, p);
    int i = object::task_error(err, p);
    この静的メンバー関数は、ランタイム・エラーの発生時に タスクシステム関数によって呼び出されます。 最初の int 型のパラメタは、「診断」の項で示すエラーコードのうちの 1 つです。 2 番目のパラメタは、通常では、この関数を呼び出したオブジェクトです。 または、エラーを処理するオブジェクトがない場合は、 ゼロにすることもできます。 静的データメンバー error_fct がゼロのとき、 task_error() は stderr ( cerr ではない) にメッセージを出力し、 exit(err) を呼び出します。 error_fct がゼロ以外のとき、 パラメタに err と p を持つユーザー関数が呼び出されます。 このユーザー関数がゼロを返すと、 task_error() もゼロを返します。 ユーザー関数がゼロ以外の値を返すと、 task_error() は上記のように exit(err) を返します。 この関数が 0 を返すと、通常では、その呼び出し側が失敗した操作を再試行します。

task *tp = o.this_task();
    task *tp = object::this_task();
    この静的メンバー関数は、 現在実行中のタスクへのポインタを返します。

  クラス Sched

クラス sched は、基本スケジューリング関数を提供します。 task と timer は、それぞれこのクラスから派生したものです。 このクラスのオブジェクトを作成することはできません。 基底クラスとしてのみ機能します。

sched s;
    sched 型のオブジェクト s を作成します (このコンストラクタが限定公開であるため、 これは正しくありません)。 コンストラクタは引数を持ちません。 オブジェクトは IDLE に初期化され、遅延はありません。

task* tp = ...;
    sched::clock_task = tp;
    静的データメンバー sched::clock_task がゼロ以外のとき、それが指すタスクはクロックが進むたびに 他のどのタスクよりも前にスケジューリングされます。 現タスクがあればブロックされ、 この「クロックタスク」が再開されます。 動作を再開するとき、クロックタスクは IDLE でなければなりません。 クロックタスクは、 task::sleep() を呼び出すことで、自身を IDLE 状態に置くことができます。

void user_exit_func(void);
    sched::exit_fct = user_exit_func;
    パラメタを何も持たずに void を返す関数を宣言し、それを静的データメンバー sched::exit_fct に割り当てることができます。 この関数は、タスクシステムから最終的に抜ける直前に呼び出されます。

int i = s.pending();
    クラス sched では、この関数はオブジェクト ( task または timer ) が TERMINATED 状態のときはゼロ以外の値 (真)、 それ以外の場合はゼロ (偽) を返します。

s.print(how);
    オブジェクトの sched 部分に関するデータを stdout ( cout ではない) に出力します。最初の int 型パラメタ how は、 object::print() に渡されます。 2 番目のパラメタは内部的に使用するもので、 デフォルトではゼロに初期化されます。 通常、この仮想関数は派生クラスから print() 関数によって呼び出します。

tp->setwho(objp)
    この関数は、クラス task と timer のために用意されています。 これらのクラスについては、後述します。 このバージョンを呼び出すとエラーになります。

s.cancel(val);
    タスクまたはタイマー s を TERMINATED 状態に置き、その戻り値として int 型の値 val を使用します。 resultis() とは異なり、 cancel() は呼び出し側の動作を中断しません。 この関数を使用すると、 あるタスクからその制御を保持したまま別のタスクを終了させることができます。

int i = s.dont_wait();
    keep_waiting() が呼び出された回数と、 dont_wait() が呼び出された回数 (この呼び出しはカウントしません) の差を 返します。 差を計算した後、カウントはデクリメントされます。 このカウントは静的変数に保持されるため、 システム単位の差を表すことになります。 このカウント値は、外部イベントを待機しているオブジェクトの数を 表していると考えられます。 後述の keep_waiting() を参照してください。

sched *tp = s.get_priority_sched();
    特殊なシステムタスクである「割り込み通知タスク」は、 待機していたシグナルが発生すると優先的にスケジューリングされます。 この関数は、そのようなタスクがスケジューリングされている場合は そのタスクへのポインタを返し、それ以外の場合はゼロを返します。 interrupt(3C++) も参照してください。

int i = s.keep_waiting();
    keep_waiting() が呼び出された回数と、 dont_wait() が呼び出された回数の差を返します。 dont_wait() のこの呼び出しも回数に含むため、 このカウンタは最初にインクリメントされます。 このカウントは静的変数に保存されるため、システムごとに異なります。 このカウントは外部イベントを待機しているオブジェクトの数を表すと 考えられます。 特に、クラス Interrupt_handler のコンストラクタは keep_waiting() を呼び出し、デストラクタは dont_wait() を呼び出します。 スケジューラはこの情報を使用するため、 割り込みハンドラの稼働時にタスクシステムが終了することはありません。

statetype t = s.rdstate();
    タスクまたはタイマー s の状態 (RUNNING、IDLE、TERMINATED のどれか) を返します。

long l = s.rdtime();
    タスクまたはタイマーを実行するようにスケジューリングされている シミュレートされた時刻を返します。

int i = s.result();
    タスク s の「結果」を返します。 この結果は、 sched::cancel()、task::cancel()、task::resultis() のどれかによって設定されます。 タスク s が終了してない場合、それが終了するまで呼び出し側タスクは中断されます。 result() を呼び出してそのタスク自身の結果を返そうとすると、エラーになります。

long l = s.getclock();
    long l = sched::getclock();
    現在のシミュレートされた時刻の値を返します。

sched* p = s.get_run_chain();
    sched* p = sched::get_run_chain();
    実行可能なタスクとタイマーのすべてのリストである 「実行チェーン」へのポインタを返します。 これらのオブジェクトは、 o_next フィールドを介してリンクされます。

int i = s.get_exit_status();
    int i = sched::get_exit_status();
    タスクシステムが正常に ( task_error() の呼び出しが原因ではなく) 終了すると、 set_exit_status() に最後に与えられた値がシステムルーチン exit() に渡されます。 この値は、デフォルトでは正常終了を示すゼロです。 関数 get_exit_status() は、 exit() に渡すために現在登録されている値を返します。

s.set_exit_status(i);
    sched::set_exit_status(i);
    int 型の値 i が保存され、タスクシステムが正常に ( task_error() の呼び出しが原因ではなく) 終了すれば、その値がシステム関数 exit() に渡されます。 set_exit_status() が一度も呼び出されない場合、その値は正常終了を示すゼロです。 それ以外の場合、 set_exit_status() に最後に渡された値が使用されます。

s.setclock(l);
    sched::setclock(l);
    シミュレートされたクロックを long 型の値 l に設定します。 システム時間はデフォルトではゼロから始まります。 この関数を 2 回以上呼び出すとエラーになります。

  クラス task

task t(name, mode, size);
    タスクを作成します。 パラメタについては、上記を参照してください。 上記のように、このコンストラクタは限定公開であるため、 task はユーザークラスの基底クラスとしてしか機能できません。

task *tp = t.t_next;
    すべてのタスクのマスターリスト上の次のタスク。 後述の get_task_chain() を参照。

unsigned char* p = t.t_name;
    コンストラクタ task によって割り当てられたタスク名へのポインタ。

objtype o = t.o_type();
    object で定義されているこの仮想関数は、オブジェクトの種類を返します。 task の場合、オブジェクトの種類は TASK になります。

t.print(how);
    task t に関するデータを stdout ( cout ではない) に出力します。 最初の int 型パラメタの how は、VERBOSE ビットと CHAIN ビットの任意の組み合わせです。 VERBOSE がセットされている場合、付加情報が出力されます。 CHAIN がセットされている場合、システム内のタスク 1 つ 1 つに関する情報が 出力されます。 このパラメタは、 sched::print() に渡されます。 2 番目のパラメタは内部的に使用されるもので、 デフォルトではゼロに設定されます。

t.setwho(objptr);
    仮想関数。 objptr が指すオブジェクトをタスク t に通知を行なったオブジェクトとして「再認識」します。 これは、タスク t がオブジェクト *objptr を待機していたとき、 そのオブジェクトの状態が「保留」から「動作可能」状態に移り、 オブジェクトがそのことをタスクに通知し、 タスク状態を IDLE から RUNNING に変更したことを意味します。 再認識されたオブジェクトは、 who_alerted_me() によって取り出すことができます。

t.cancel(val);
    タスク t を TERMINATED 状態に置き、 int 型の値 val をその戻り値として使用します。 resultis() とは異なり、cancel() は呼び出し側の動作を中断しません。 これにより、1 つのタスクからその制御を保持したまま 別のタスクを終了させることができます。 resultis() も参照してください。

t.delay(n);
    シミュレートされた単位時間 n が経過する間、タスク t を中断し、その状態を RUNNING のままにします。 残っている遅延時間が最も短い RUNNING 状態のタスクが制御を取得し、 シミュレートされたクロックはその継続時間まで進みます。 クロックが n 単位進むと、タスク t は実行を再開します。 delay() を使用しないと、クロックを進めることはできません。

int i = t.preempt();
    RUNNING 状態のタスク t を中断し、それを IDLE 状態にします。 この関数は、 t が実行を続けるようにスケジューリングされている時刻までに 残っている単位時間の数を返します。 IDLE または TERMINATED 状態のタスクに対して preempt() を呼び出すとエラーになります。

t.resultis(val);
    タスク t を TERMINATED 状態に置き、 int 型の値 val をその戻り値として使用します。 この値は、 t.result() を呼び出すことで検査できます。 タスク t に対して result() を呼び出し、そのタスクが終了するのを待機しているすべてのタスクに対し、 通知が行われます。 タスクは、関数が通常使用する方法で値を返すことができないため、 終了するときには resultis() または cancel() を呼び出す必要があります。 すべてのタスクは、それが終了するまで「保留」状態になります。

t.sleep(objptr);
    タスク t を無条件に中断し IDLE 状態にします。 省略可能な引数 objptr は、タスク t を「再認識」し、オブジェクトが動作可能になったときに それに通知するオブジェクトへのポインタです。 wait() とは異なり、 sleep() はオブジェクトが保留中かどうかを最初にチェックしません。 タスクは常に中断されます。

t.wait(objptr);
    objptr が指すオブジェクトが保留中であれば、 タスク t を中断 (IDLE 状態に) します。 この場合、そのオブジェクトは動作可能になると、 そのことを t に通知します (タスクを RUNNNING 状態に置き、「実行チェーン」に戻します)。 オブジェクトが保留中でない場合、タスク t は中断されず、制御を保持したままとなります。

int which = t.waitlist(op1, op2, ... , NULL);
    この関数は、NULL ポインタで終わるオブジェクトへのポインタのリストを 引数として受け取ります。 指定されたすべてのオブジェクトが保留中の場合、 タスク t はそれらのどれかが動作可能になるまで中断されます。 この関数は、タスクの少なくとも 1 つが動作可能になると終了し、 終了の原因となったオブジェクトのリストのインデックス (0 から始まる) を 返します。この時点で、 リストの中の他のオブジェクトも動作可能な場合があります。 waitlist() の呼び出しまでに保留されているオブジェクトがないと、 タスク t は中断されず、 waitlist() は直ちに終了します。

int which = t.waitvec(objarray);
    この関数は、 waitlist() とちょうど同じ働きをします。 ただし、 waitlist() が引数として可変長のリストを受け取るのに対し、 この関数はオブジェクトへのポインタの配列を受け取ります。 配列は、NULL ポインタで終わります。

task *tp = t.get_task_chain();
    task *tp = task::get_task_chain();
    この静的メンバー関数は、すべてのタスクのリストの先頭を返します。 システム内のすべてのタスクは (RUNNING、IDLE、TERMINATED どの状態であっても)、 データメンバー t_next を介してリンクされ、このリストに含まれています。

  クラス timer

timer tm(d);
    シミュレートされた単位時間 d で終了するタイマーを作成します。 このタイマーは「実行チェーン」に置かれます。

objtype o = tm.o_type();
    object で定義されているこの仮想関数は、オブジェクトの種類を返します。 timer, の場合、オブジェクトの種類は TIMER になります。

tm.print(how);
    タイマー tm に関する情報を stdout ( cout ではない) に出力します。先頭の int 型パラメタである how は sched::print() に渡されます。 第 2 引数は内部で使用されるもので、デフォルトではゼロに設定されます。

tm.setwho(objptr);
    この仮想関数はタイマーには効果がありません。 タイマーには通知できないからです。

tm.reset(d);
    タイマー tm の遅延を シミュレートされた単位時間 d に再設定します。 終了しているタイマーでも再設定することができます。 すなわち、タイマーは再使用できるため、使用するたびに作成したり、 破棄する必要はありません。

診断

前述のように、 タスクシステムはランタイム・エラーを検出すると、 object::task_error() を呼び出します。 次の表は、考えられる各エラーの値と対応するメッセージとその意味を示しています。
エラー名 | メッセージ | 説明
E_ERROR | (メッセージなし) | 未定義のエラー
E_OLINK | object::delete(): has chain | 1 つまたは複数のオブジェクトが登録されているリメンバ・チェーンを持つ オブジェクトを破棄しようとした。
E_ONEXT | object::delete(): on chain | リストに含まれているオブジェクトを破棄しようとした。
E_GETEMPTY | qhead::get(): empty | 空のキューからの取得を試みた。
E_PUTOBJ | qtail::put(): object on other queue | すでにキューにあるオブジェクトをキューに置こうとした。
E_PUTFULL | qtail::put(): full | フル状態のキューにオブジェクトを置こうとした。
E_BACKOBJ | qhead::putback(): object on other queue | すでにキューにあるオブジェクトをキューに戻そうとした。
E_BACKFULL | qhead::putback(): full | フル状態のキューにオブジェクトを戻そうとした。
E_SETCLOCK | sched::setclock(): clock!=0 | クロックを 2 度設定しようとした。
E_CLOCKIDLE | sched::schedule(): clock_task not idle | クロックタスクの実行をスケジューリングしようとしたとき、 そのクロックタスクは IDLE 状態ではなかった。
E_RESTERM | sched::insert(): cannot schedule terminated sched | TERMINATED 状態のタスクを再開しようとした。
E_RESRUN | sched::schedule(): running | RUNNING 状態のタスクを再開しようとした。
E_NEGTIME | sched::schedule(): clock<0 | クロックを負の値に設定しようとしたか、負の遅延を使用しようとした。
E_RESOBJ | sched::schedule(): task or timer on other queue | すでにキューに置かれているタスクを再開しようとした。
E_HISTO | histogram::histogram(): bad arguments | ヒストグラムのコンストラクタに対し、矛盾した引数、または不正な引数が 渡された。
E_STACK | task::task() or task::resume(): stack overflow | ランタイムタスクのスタックがオーバーフローした。
E_STORE | new: free store exhausted | タスク記録のための空き領域がない。
E_TASKMODE | task::task(): bad mode | タスク・コンストラクタに対し、不正なモード引数が渡された。
E_TASKDEL | task::~task(): not terminated | TERMINATED 状態ではないタスクを破棄しようとした。
E_TASKPRE | task::preempt(): not running | RUNNING 状態でないタスクに対し preempt を実行しようとした。
E_TIMERDEL | timer::~timer(): not terminated | TERMINATED 状態でないタスクを破棄しようとした。
E_SCHTIME | sched::schedule(): runchain corrupted: bad time | 実行チェーンが破棄され、時間順になっていない。
E_SCHOBJ | sched object used directly (not as base) | 派生したタスクまたはタイマーではなく、sched オブジェクトを使用しようとした。
E_QDEL | queue::~queue(): not empty | 空でないキューを破棄しようとした。
E_RESULT | task::result(): thistask->result() | タスクが自分自身に対して result() を呼び出そうとした。
E_WAIT | task::wait(): wait for self | タスクが自分自身を待機しようとした。
E_FUNCS | FrameLayout::FrameLayout(): function start | (未使用)
E_FRAMES | FrameLayout::FrameLayout(): frame size | (未使用)
E_REGMASK | task::fudge_return(): unexpected register mask | (未使用)
E_FUDGE_SIZE | task::fudge_return(): frame too big | (未使用)
E_NO_HNDLR | signal_handler - no handler for signal | シグナルが発生したが、ハンドラが登録されていない。
E_BADSIG | シグナル番号が不正。 | 不正なシグナル番号を登録しようとした。
E_LOSTHNDLR | Interrupt_handler:: ~Interrupt_handler(): signal handler not on chain | 内部エラー : シグナル・ハンドラが失われた。
E_RUNCHAIN | sched::sched(): run chain empty | すべてのタスクが終了し、割り込みハンドラが何も存在しない。

注意事項
この製品出荷の時点では、コルーチンライブラリが現在のバージョン上では サポートされません。

関連項目
task.intro(3C++)、 interrupt(3C++)、 queue(3C++)、 tasksim(3C++)、 exit(3C)