前へ | 次へ | 目次 | 索引 |
プログラマは,ブロードキャスト時にすべてのスレッドが条件変数を待っているようにするか,またはブロードキャストがすでに起こったことを対応する述語で明らかにすることによって,そのブロードキャストが確実に認識されるようにしなければならない。このような方法は,この例では意図的に省いている。
デバッガを使用すればスレッドの相対的な実行を制御することにより,例 17-1 のような問題を診断することができます。この例の場合は,初期スレッドの実行を中断してワーカ・スレッドに計算を終了させ,ワーカ・スレッドがブロードキャスト時に条件変数を待っているようにできます。その手順は次のとおりです。
例 17-2 はデバッグ中のタスキング・プログラムによくあるエラーを示します。この例のプロシージャ BREAK の呼び出しは,ブレークポイントを設定したり各タスクの状態を観察する候補箇所です。この例をデバッガ制御の下で実行する場合は,プロシージャ BREAK の各呼び出しの箇所で次のコマンドを入力してブレークポイントを設定し,それぞれのブレークポイントで各タスクのそのときの状態を表示できます。
DBG> SET BREAK %LINE 46 DO(SHOW TASK/ALL) DBG> SET BREAK %LINE 71 DO(SHOW TASK/ALL) DBG> SET BREAK %LINE 76 DO(SHOW TASK/ALL) DBG> SET BREAK %LINE 92 DO(SHOW TASK/ALL) DBG> SET BREAK %LINE 100 DO(SHOW TASK/ALL) DBG> SET BREAK %LINE 104 DO(SHOW TASK/ALL) DBG> SET BREAK %LINE 120 DO(SHOW TASK/ALL) |
このプログラムでは次の 4 つのタスクが作成されます。
例 17-2 Adaのタスキング・プログラムの例 |
---|
1 -- Tasking program that demonstrates various tasking conditions. 2 3 package TASK_EXAMPLE_PKG is 4 procedure BREAK; 5 end; 6 7 package body TASK_EXAMPLE_PKG is 8 procedure BREAK is 9 begin 10 null; 11 end; 12 end; 13 14 15 with TEXT_IO; use TEXT_IO; 16 with TASK_EXAMPLE_PKG; use TASK_EXAMPLE_PKG; 17 procedure TASK_EXAMPLE is (1) 18 19 pragma TIME_SLICE(0.0); -- Disable time slicing. (2) 20 21 task type FATHER_TYPE is 22 entry START; 23 entry RENDEZVOUS; 24 entry BOGUS; -- Never accepted, caller deadlocks. 25 end FATHER_TYPE; 26 27 FATHER : FATHER_TYPE; (3) 28 29 task body FATHER_TYPE is 30 SOME_ERROR : exception; 31 32 task CHILD is (4) 33 entry E; 34 end CHILD; 35 36 task body CHILD is 37 begin 38 FATHER_TYPE.BOGUS; -- Deadlocks on call to its parent 39 end CHILD; --(parent does not have an accept 40 -- statement for entry BOGUS). Whenever 41 -- a task-type name(here, FATHER_TYPE) 42 -- is used within a task body, the 43 -- name designates the task currently 44 -- executing the body. 45 begin --(of FATHER_TYPE body) 46 47 accept START do 48 BREAK; -- Main program is waiting for this rendezvous to 49 -- complete; CHILD is suspended when it calls the 50 -- entry BOGUS. 51 null; 52 end START; 53 54 PUT_LINE("FATHER is now active and"); (5) 55 PUT_LINE("is going to rendezvous with main program."); 56 57 for I in 1..2 loop 58 select 59 accept RENDEZVOUS do 60 PUT_LINE("FATHER now in rendezvous with main program"); 61 end RENDEZVOUS; 62 or 63 terminate; 64 end select; 65 66 if I = 2 then 67 raise SOME_ERROR; 68 end if; 69 end loop; 70 71 exception 72 when OTHERS => 73 BREAK; -- CHILD is suspended on entry call to BOGUS. 74 -- Main program is going to delay while FATHER 75 -- terminates. 76 -- MOTHER is ready to begin executing. 77 abort CHILD; 78 BREAK; -- CHILD is now abnormal due to the abort statement. 79 80 raise; -- SOME_ERROR exception terminates FATHER. 81 end FATHER_TYPE; 82 83 begin --(of TASK_EXAMPLE) (6) 84 85 declare 86 task MOTHER is (7) 87 entry START; 88 pragma PRIORITY(6); 89 end MOTHER; 90 91 task body MOTHER is 92 begin 93 accept START; 94 BREAK; -- At this point, the main program is waiting for 95 -- its dependents(FATHER and MOTHER)to terminate. 96 -- FATHER is terminated. 97 null; 98 end MOTHER; 99 begin (8) 100 101 102 BREAK; -- FATHER is suspended at accept start. 103 -- CHILD is suspended in its deadlock. 104 -- MOTHER has activated and ready to begin executing. 105 FATHER.START; (9) 106 BREAK; -- FATHER is suspended at its 'select or terminate' 107 -- statement. 108 109 110 FATHER.RENDEZVOUS; 111 FATHER.RENDEZVOUS; (10) 112 loop (11) 113 -- This loop causes the main program to busy wait 114 -- for the termination of FATHER, so that FATHER 115 -- can be observed in its terminated state. 116 if FATHER'TERMINATED then 117 exit; 118 end if; 119 delay 1.0; 120 end loop; 121 122 BREAK; -- FATHER has terminated by now with the unhandled 123 -- exception SOME_ERROR. CHILD no longer exists 124 -- because its master(FATHER)has terminated. Task 125 -- MOTHER is ready. 126 MOTHER.START; (12) 127 -- The main program enters a wait-for-dependents state, 128 -- so that MOTHER can finish executing. 129 end; 130 end TASK_EXAMPLE; (13) |
次の番号は,例 17-2 の番号に対応しています。
VAX プロセッサでは,プラグマ TIME_SLICE を省略するか値 0.0 を指定すると,タイム・スライス機能は禁止される。
Alpha プロセッサでは,タイム・スライス機能を禁止するためにプラグマ TIME_SLICE(0.0)を使用しなければならない。
起動されたタスク FATHER は,タスク CHILD が起動され,%TASK 3 を指定されたタスクが作成されるのを待つ。CHILD は行 38 で 1 つのエントリ呼び出しを実行し,そのエントリが受け付けられないのでデッドロックになる(第 17.7.1 項 を参照)。
タイム・スライス機能が禁止され,優先順位の高い実行可能なタスクがないので,FATHER は起動後も行 47 の ACCEPT 文でブロックされるまで実行される。
タスク とは,その他のタスクと並行して実行される要素です。タスクには固有のタスク ID(第 17.3.3 項 を参照),独立したスタック,および独立したレジスタ・セットが与えられます。
アクティブ・タスクと可視タスクの現在の定義により,タスク操作のコンテキストが決まります。第 17.3.1 項 を参照してください。
デバッガ・コマンドにタスクを指定するときには,次のいずれかの形式で指定できます。
アクティブ・タスクとは,STEP,GO,CALL,または EXIT コマンドを実行したときに起動されるタスクです。プログラムをデバッガの制御下に置くと,最初はアクティブ・タスクの中で実行が中断されます。デバッグ・セッション中にアクティブ・タスクを変更するには SET TASK/ACTIVE コマンドを使用します。
SET TASK/ACTIVE コマンドは,POSIX Threads 経由で実行するタスキング,POSIX Threads(OpenVMS Alpha システムと VAX システムの両方で)と Ada(OpenVMS Alpha システムで)の両方で動作しません。POSIX Threads で照会型のアクションを行うときは,SET TASK/ACTIVE コマンドの代わりに,SET TASK/VISIBLE コマンドを使用します。特定のスレッドでステップを制御したいときは,ブレークポイントを適切な位置に配置します。 |
次のコマンドでは CHILD というタスクがアクティブ・タスクになります。
DBG> SET TASK/ACTIVE CHILD |
可視タスク とは,スタックとレジスタ・セットがデバッガによって現在のコンテキストとして使用されるタスクです。デバッガはシンボル,レジスタ値,ルーチン呼び出し,ブレークポイントなどを参照するときにスタックとレジスタ・セットを使用します。たとえば,次のコマンドでは,可視タスクのコンテキストの変数 KEEP_COUNT の値が表示されます。
DBG> EXAMINE KEEP_COUNT |
最初は,可視タスクがアクティブ・タスクです。可視タスクを変更するには,SET TASK/VISIBLE コマンドを使用します。このコマンドにより,アクティブ・タスクに影響を与えずにその他のタスクの状態を参照することができます。
デバッガ・コマンドに組み込みシンボルの %ACTIVE_TASK と %VISIBLE_TASK を使用することにより,それぞれアクティブ・タスクと可視タスクを指定できます(第 17.3.4 項 を参照)。
SET TASK コマンドによるタスク特性の変更についての詳しい説明は,第 17.5 節 を参照してください。
17.3.2 Adaのタスキングの構文
タスクを宣言するには,単一タスクを宣言するか,またはあるタスク型のオブジェクトを宣言します。次に例を示します。
-- タスク型の宣言。 -- task type FATHER_TYPE is ... end FATHER_TYPE; task body FATHER_TYPE is ... end FATHER_TYPE; -- 単一タスク。 -- task MOTHER is ... end MOTHER; task body MOTHER is ... end MOTHER; |
タスク・オブジェクト とは,タスク値を含むデータ項目です。タスク・オブジェクトが作成されるのは,プログラムによって単一タスクかタスク・オブジェクトが作成されるとき,タスク構成要素を含んでいる配列かレコードをユーザが宣言するとき,またはタスク・アロケータが評価されるときです。次に例を示します。
-- タスク・オブジェクトの宣言。 -- FATHER : FATHER_TYPE; -- タスク・オブジェクト(T)はレコードの構成要素。 -- type SOME_RECORD_TYPE is record A, B: INTEGER; T : FATHER_TYPE; end record; HAS_TASK : SOME_RECORD_TYPE; -- タスク・オブジェクト(POINTER1)はアロケータを通じて作成される。 -- type A is access FATHER_TYPE; POINTER1 : A := new FATHER_TYPE; |
タスク・オブジェクトは,その他のオブジェクトに似ています。デバッガ・コマンドにタスク・オブジェクトを指定するときには,名前かパス名を指定します。次に例を示します。
DBG> EXAMINE FATHER DBG> EXAMINE FATHER_TYPE$TASK_BODY.CHILD |
タスク・オブジェクトを作成すると,Compaq Ada 実行時ライブラリによってタスクが作成され,そのタスク・オブジェクトにタスク値が割り当てられます。タスク・オブジェクトの値はその他の Ada オブジェクトと同じく,オブジェクトが初期化されるまでは未定義になるので,初期化されていない値を使用するとその結果は予測できません。
あるタスク型または単一タスクの タスク本体 は,1 つのプロシージャとして Compaq Ada の中に組み込まれます。そのプロシージャはその型のタスクが起動されるとき,Compaq Ada の実行時ライブラリから呼び出されます。デバッガはタスク本体を普通のAdaプロシージャとして処理します。特別な構造の名前を持っている点が異なります。
デバッガ・コマンドにタスク本体を指定するには,次の構文を使用して,タスク型として宣言されているタスクを指定します。
task-type-identifier$TASK_BODY |
単一タスクの指定には,次の構文を使用します。
task-identifier$TASK_BODY |
たとえば,次のように指定します。
DBG> SET BREAK FATHER_TYPE$TASK_BODY |
デバッガはタスク依存の Ada 属性 T'CALLABLE,E'COUNT,T'STORAGE_SIZE,および T'TERMINATED はサポートしません。このうち,T はタスク型,E はタスク・エントリです(これらの属性についての詳しい説明は,Compaq Ada の資料を参照してください)。EVALUATE CHILD'CALLABLE などのコマンドは入力できません。しかし,デバッガの SHOW TASK コマンドを使用してこれらの属性の内容を知ることはできます。詳しい説明は,第 17.4 節 を参照してください。
前へ | 次へ | 目次 | 索引 |