# マニュアルページ task.3

## 名前

         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、 TER-
              MINATED のどれか) を返します。

         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() とは異なり、can-
              cel() は呼び出し側の動作を中断しません。これによ り、 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():     1 つまたは複数の
                          has chain             オブジェクトが登
                                                録されているリメ
                                                ンバ・チェーンを
                                                持つオブジェクト
                                                を破棄しようとし
                                                た。
             ___________________________________________________
             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():    クロックを 2  度
                          clock!=0              設 定 しようとし
                                                た。
             ___________________________________________________
             E_CLOCKIDLE  sched::schedule():    クロックタスクの
                          clock_task not idle   実行をスケジュー
                                                リングしようとし
                                                た と き、そのク
                                                ロックタス ク は
                                                IDLE  状態ではな
                                                かった。
             ___________________________________________________
             E_RESTERM    sched::insert():      TERMINATED 状 態
                          cannot schedule ter-  のタスクを再開し
                          minated sched         ようとした。
             ___________________________________________________
             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)