日本-日本語 |
|
|
|
OpenVMS マニュアル |
|
HP OpenVMS
|
目次 | 索引 |
本章では,タスキング・プログラム ( マルチスレッド・プログラムとも呼ぶ ) に固有のデバッガ機能について説明します。タスキング・プログラムは 1 つのプロセス内に複数のタスクまたは実行スレッドを持っています。デバッガで使用する タスク という用語は制御の流れのことであり,言語や実現方法とは関係ありません。デバッガのタスキング・サポートは,それらのプログラムすべてに適用されます。次のものを含んでいます。
注意 デバッガの中では,タスクとスレッドという用語は同義語として使われます。 PTHREAD$RTL バージョン 7.1 またはそれ以降のバージョンがリンクされたプログラムをデバッグするときには,PTHREAD コマンドを使って POSIX Threads デバッガに直接アクセスすることができます。 |
本章では, POSIX Threads 固有か言語固有の情報にはそのことを明記します。 第 16.1 節 に POSIX Threads 用語と Ada のタスキング用語の対応表を示します。
本章の機能を使用すれば,次のような処理を行うことができます。
これらの機能を使用するときには,同じタスキング・プログラムを実行してもそのときの状況によっては動作がデバッガにより変更されることがあるので注意してください。たとえば,現在アクティブなタスクの実行をあるブレークポイントで中断しているとき,入出力 (I/O) の終了による POSIX 信号か非同期システム・トラップ (AST) が届いた場合は,ユーザの続行指示後ただちにその他のタスクが適格になることがあります。
POSIX Threads についての詳しい説明は,『Guide to the POSIX Threads Library』を参照してください。 Ada タスクについての詳しい説明は Ada のマニュアルを参照してください。
マルチプロセス・プログラム(2つ以上のプロセスに分けて実行されるプログラム)のデバッグについては 第 15 章 を参照してください。
16.1 POSIX Threads 用語とAda用語の対応表
表 16-1 に POSIX Threads と Ada の用語とその意味の対応を示します。
POSIX Threads 用語 | Ada用語 | 意味 |
---|---|---|
スレッド | タスク | 同じプロセス内の制御の流れ |
スレッド・オブジェクト | タスク・オブジェクト | 制御の流れを表すデータ項目 |
オブジェクト名または式 | タスク名または式 | 制御の流れを表すデータ項目 |
開始ルーチン | タスク本体 | 制御の流れに従って実行されるコード |
該当なし | 親タスク | 親タスクの制御の流れ |
該当なし | 依存タスク | なんらかの親タスクに制御される子タスクの制御の流れ |
同期化オブジェクト(ミューテクス,条件変数) | ランデブ構造 ( エントリ呼び出しやaccept文など ) | 制御の流れを同期化する方法 |
スケジューリング方針およびスケジューリング優先順位 | タスク優先順位 | 実行のスケジューリング方法 |
警告処理 | abort文 | 制御の流れの取り消し方法 |
スレッド状態 | タスク状態 | 実行の状態 ( 待ち,レディ,実行中,終了) |
スレッド作成属性 ( 優先順位,スケジューリング方針など ) | プラグマ | パラレル・エンティティの属性 |
次の各項では,タスキング・プログラムのデバッグ時によく起こるエラーを含んでいるタスキング・プログラムの例を示します。
本章のその他の例は,これらのプログラムを引用したものです。
例 16-1 はマルチスレッドの C のプログラムです。条件変数の使用法が間違っているのでブロッキングを起こします。
例のあとに説明が続いています。その説明のあとに,デバッガを使用してスレッドの相対的な実行を制御することによってブロッキングを診断する方法を示しています。
例 16-1 では,初期スレッドにより,計算作業を行う 2 つのワーカ・スレッドが作成されます。これらのワーカ・スレッドの作成後に SHOW TASK/ALL コマンドを実行すれば,それぞれが 1 つのスレッドに対応する 4 つのタスクが表示されます。 第 16.4 節 に SHOW TASK コマンドの使用法が説明されています。
例 16-1 では,ワーカ・スレッドのパスの行 3893 に同期化点 ( 条件待ち ) が設けられています。行 3877 から始まるコメントは,このような直接的な呼び出しは間違ったプログラミング方法であることを示したうえで,正しいコーディング方法を示しています。
このプログラムを実行すると,ワーカ・スレッドが大量の計算を行っているときに初期スレッドが条件変数をブロードキャストします。条件変数をモニタしている最初のスレッドは初期スレッドのブロードキャストを検出してクリアし,残りのスレッドを放置します。実行が妨げられ,プログラムは終了できなくなります。
16.2 タスキング・プログラムの例
16.2.1 Cのマルチスレッド・プログラムの例
例 16-1 Cのマルチスレッド・プログラムの例 |
---|
3777 /* 定義 */ 3778 #define NUM_WORKERS 2 /* ワーカ・スレッドの数 */ 3779 3780 /* マクロ */ 3781 #define check(status,string) \ 3782 if (status == -1) perror (string); \ 3783 3784 /* グローバル変数 */ 3785 int cv_pred1; /* 条件変数の述語 */ 3786 pthread_mutex_t cv_mutex; /* 条件変数のミューテクス */ 3787 pthread_cond_t cv; /* 条件変数 */ 3788 pthread_mutex_t print_mutex; /* プリント・ミューテクス */ 3789 3790 /* ルーチン */ 3791 static pthread_startroutine_t 3792 worker_routine (pthread_addr_t arg); 3793 3794 main () 3795 { 3796 pthread_t threads[NUM_WORKERS]; /* ワーカ・スレッド */ 3797 int status; /* 戻り状態値 */ 3798 int exit; /* Join終了状態値 */ 3799 int result; /* Join結果値 */ 3800 int i; /* ループ索引 */ 3801 3802 /* ミューテクスの初期化 */ 3803 status = pthread_mutex_init (&cv_mutex, pthread_mutexattr_default); 3804 check (status, "cv_mutex initilization bad status"); 3805 status = pthread_mutex_init (&print_mutex, pthread_mutexattr_default); 3806 check (status, "print_mutex intialization bad status"); 3807 3808 /* 条件変数の初期化 */ 3809 status = pthread_cond_init (&cv, pthread_condattr_default); 3810 check (status, "cv condition init bad status"); 3811 3812 /* 条件変数の述語の初期化 */ 3813 cv_pred1 = 1; (1) 3814 3815 /* ワーカ・スレッドの作成 */ 3816 for (i = 0; i < num_workers; i++) { (2) 3817 status = pthread_create ( 3818 &threads[i], 3819 pthread_attr_default, 3820 worker_routine, 3821 0); 3822 check (status, "threads create bad status"); 3823 } 3824 3825 /* cv_pred1を偽に設定。可視性を保つためにロック内で行う。*/ 3826 3827 status = pthread_mutex_lock (&cv_mutex); 3828 check (status, "cv_mutex lock bad status"); 3829 3830 cv_pred1 = 0; (3) 3831 3832 status = pthread_mutex_unlock (&cv_mutex); 3833 check (status, "cv_mutex unlock bad status"); 3834 3835 /* ブロードキャストの実施 */ 3836 status = pthread_cond_broadcast (&cv); (4) 3837 check (status, "cv broadcast bad status"); 3838 3839 /* 両方のワーカ・スレッドの結合を試行 */ 3840 for (i = 0; i < num_workers; i++) { (5) 3841 exit = pthread_join (threads[i], (pthread_addr_t*)&result); 3842 check (exit, "threads join bad status"); 3843 } 3844 } 3845 3846 static pthread_startroutine_t 3847 worker_routine(arg) 3848 pthread_addr_t arg; (6) 3849 { 3850 int sum; 3851 int iterations; 3852 int count; 3853 int status; 3854 3855 /* 大量の計算を実施 */ 3856 for (iterations = 1; iterations < 10001; iterations++) { 3857 sum = 1; 3858 for (count = 1; count < 10001; count++) { 3859 sum = sum + count; 3860 } 3861 } 3862 3863 /* Printfはリエントラントとは限らないので,一度に1スレッドを実行 */ 3864 3865 status = pthread_mutex_lock (&print_mutex); 3866 check (status, "print_mutex lock bad status"); 3867 printf (" The sum is %d \n", sum); 3868 status = pthread_mutex_unlock (&print_mutex); 3869 check (status, "print_mutex unlock bad status"); 3870 3871 /* この条件変数のミューテクスをロックする。スレッドにより条件変数がブ*/ 3872 /* ロックされるとpthread_condによりそのミューテクスがアンロックされる*/ 3873 3874 status = pthread_mutex_lock (&cv_mutex); 3875 check (status, "cv_mutex lock bad status"); 3876 3877 /* 次の文では,条件待ち呼び出しのまわりをループし,その条件変数の述 */ 3878 /* 語をチェックするのが正しい条件待ちの構文ということになります。 */ 3879 /* そうすれば,ブロードキャスト済みの可能性がある条件変数を待った */ 3880 /* り,間違ったウェイクアップによって起動されるのを回避できます。そ */ 3881 /* のスレッドがウェイクアップされ,しかもその述語が偽であれば,実 */ 3882 /* 行が再開されます。正しい呼び出しは,たとえば次のようになります。 */ 3883 /* */ 3884 /* while (cv_pred1) { */ 3885 /* status = pthread_cond_wait (&cv, &cv_mutex); */ 3886 /* check (status, "cv condition wait bad status"); */ 3887 /* } */ 3888 /* */ 3889 /* 次のコーディングで使用されているような直接的な呼び出しでは, */ 3890 /* スレッドが間違ってウェイクアップされたり,この例のワーカ・ */ 3891 /* スレッドの1つと同様に永続的にブロックされることがあります。 */ 3892 3893 status = pthread_cond_wait (&cv, &cv_mutex); (7) 3894 check (status, "cv condition wait bad status"); 3895 3896 /* 条件待ちでブロックされている間,そのルーチンはミューテクスを手放 */ 3897 /* しますが,制御が戻ったらミューテクスを取り出します。 */ 3898 3899 status = pthread_mutex_unlock (&cv_mutex); 3900 check (status, "cv_mutex unlock bad status"); 3901 3902 return (int)arg; 3903 } |
次の番号は, 例 16-1 の番号に対応しています。
デバッガを使用すればスレッドの相対的な実行を制御することにより, 例 16-1 のような問題を診断することができます。この例の場合は,初期スレッドの実行を中断してワーカ・スレッドに計算を終了させ,ワーカ・スレッドがブロードキャスト時に条件変数を待っているようにできます。その手順は次のとおりです。
例 16-2 はデバッグ中のタスキング・プログラムによくあるエラーを示します。ここで示すのは,OpenVMS Alpha 上で動作している OpenVMS デバッガの例です。この例のプロシージャ BREAK の呼び出しは,ブレークポイントを設定したり各タスクの状態を観察する候補箇所です。この例をデバッガ制御の下で実行する場合は,プロシージャ BREAK の各呼び出しの箇所で次のコマンドを入力してブレークポイントを設定し,それぞれのブレークポイントで各タスクのそのときの状態を表示できます。
DBG> SET BREAK %LINE 37 DO (SHOW TASK/ALL) DBG> SET BREAK %LINE 61 DO (SHOW TASK/ALL) DBG> SET BREAK %LINE 65 DO (SHOW TASK/ALL) DBG> SET BREAK %LINE 81 DO (SHOW TASK/ALL) DBG> SET BREAK %LINE 87 DO (SHOW TASK/ALL) DBG> SET BREAK %LINE 91 DO (SHOW TASK/ALL) DBG> SET BREAK %LINE 105 DO (SHOW TASK/ALL) |
このプログラムでは次の 4 つのタスクが作成されます。
例 16-2 Adaのタスキング・プログラムの例 |
---|
1 --Tasking program that demonstrates various tasking conditions. 2 3 with TEXT_IO; use TEXT_IO; 4 procedure TASK_EXAMPLE is (1) 5 6 pragma TIME_SLICE(0.0); -- Disable time slicing. (2) 7 8 task type FATHER_TYPE is 9 entry START; 10 entry RENDEZVOUS; 11 entry BOGUS; -- Never accepted, caller deadlocks. 12 end FATHER_TYPE; 13 14 FATHER : FATHER_TYPE; (3) 15 16 task body FATHER_TYPE is 17 SOME_ERROR : exception; 18 19 task CHILD is (4) 20 entry E; 21 end CHILD; 22 23 task body CHILD is 24 begin 25 FATHER_TYPE.BOGUS; -- Deadlocks on call to its parent. 26 end CHILD; -- Whenever a task-type name 27 -- (here, FATHER_TYPE) is used within the 28 -- task body, the name denotes the task 29 -- currently executing the body. 30 begin -- (of FATHER_TYPE body) 31 32 accept START do 33 -- Main program is now waiting for this rendezvous completion, 34 -- and CHILD is suspended when it calls the entry BOGUS. 35 36 null; 37 <<B1>> end START; 38 39 PUT_LINE("FATHER is now active and"); (5) 40 PUT_LINE("is going to rendezvous with main program."); 41 42 for I in 1..2 loop 43 select 44 accept RENDEZVOUS do 45 PUT_LINE("FATHER now in rendezvous with main program"); 46 end RENDEZVOUS; 47 or 48 terminate; 49 end select; 50 51 if I = 2 then 52 raise SOME_ERROR; 53 end if; 54 end loop; 55 56 exception 57 when OTHERS => 58 -- CHILD is suspended on entry call to BOGUS. 59 -- Main program is going to delay while FATHER terminates. 60 -- Mother in suspended state with "Not yet activated" sub state. 61<<B2>> abort CHILD; 62 -- CHILD is now abnormal due to the abort statement. 63 64 65<<B3>> raise; -- SOME_ERROR exception terminates 66 FATHER. 67 end FATHER_TYPE; (6) 68 69 task MOTHER is (7) 70 entry START; 71 pragma PRIORITY (6); 72 end MOTHER; 73 74 task body MOTHER is 75 begin 76 accept START; 77 -- At this point, the main program is waiting for its dependents 78 -- (FATHER and MOTHER) to terminate. FATHER is terminated. 79 80 null; 81<<B4>> end MOTHER; 82 83 begin -- (of TASK_EXAMPLE)(8) 84 -- FATHER is suspended at accept start, and 85 -- CHILD is suspended in its deadlock. 86 -- Mother in suspended state with "Not yet activated" sub state. 87<<B5>> FATHER.START; (9) 88 -- FATHER is suspended at the 'select' or 'terminate' statement. 89 90 91<<B6>> FATHER.RENDEZVOUS; 92 FATHER.RENDEZVOUS; (10) 93 loop (11) 94 -- This loop causes the main program to busy wait for termination of 95 -- FATHER, so that FATHER can be observed in its terminated state. 96 if FATHER'TERMINATED then 97 exit; 98 end if; 99 delay 10.0; -- 10.0 so that MOTHER is suspended 100 end loop; -- at the 'accept' statement (increases determinism). 101 102 -- FATHER has terminated by now with an unhandled 103 -- exception, and CHILD no longer exists because its 104 -- master (FATHER) has terminated. Task MOTHER is ready. 105<<B7>> MOTHER.START; (12) 106 -- The main program enters a wait-for-dependents state 107 -- so that MOTHER can finish executing. 108 end TASK_EXAMPLE; (13) 1 --Tasking program that demonstrates various tasking conditions. 2 3 with TEXT_IO; use TEXT_IO; 4 procedure TASK_EXAMPLE is (1) 5 6 pragma TIME_SLICE(0.0); -- Disable time slicing. (2) 7 8 task type FATHER_TYPE is 9 entry START; 10 entry RENDEZVOUS; 11 entry BOGUS; -- Never accepted, caller deadlocks. 12 end FATHER_TYPE; 13 14 FATHER : FATHER_TYPE; (3) 15 16 task body FATHER_TYPE is 17 SOME_ERROR : exception; 18 19 task CHILD is (4) 20 entry E; 21 end CHILD; 22 23 task body CHILD is 24 begin 25 FATHER_TYPE.BOGUS; -- Deadlocks on call to its parent. 26 end CHILD; -- Whenever a task-type name 27 -- (here, FATHER_TYPE) is used within the 28 -- task body, the name denotes the task 29 -- currently executing the body. 30 begin -- (of FATHER_TYPE body) 31 32 accept START do 33 -- Main program is now waiting for this rendezvous completion, 34 -- and CHILD is suspended when it calls the entry BOGUS. 35 36 null; 37 <<B1>> end START; 38 39 PUT_LINE("FATHER is now active and"); (5) 40 PUT_LINE("is going to rendezvous with main program."); 41 42 for I in 1..2 loop 43 select 44 accept RENDEZVOUS do 45 PUT_LINE("FATHER now in rendezvous with main program"); 46 end RENDEZVOUS; 47 or 48 terminate; 49 end select; 50 51 if I = 2 then 52 raise SOME_ERROR; 53 end if; 54 end loop; 55 56 exception 57 when OTHERS => 58 -- CHILD is suspended on entry call to BOGUS. 59 -- Main program is going to delay while FATHER terminates. 60 -- Mother in suspended state with "Not yet activated" sub state. 61<<B2>> abort CHILD; 62 -- CHILD is now abnormal due to the abort statement. 63 64 65<<B3>> raise; -- SOME_ERROR exception terminates 66 FATHER. 67 end FATHER_TYPE; (6) 68 69 task MOTHER is (7) 70 entry START; 71 pragma PRIORITY (6); 72 end MOTHER; 73 74 task body MOTHER is 75 begin 76 accept START; 77 -- At this point, the main program is waiting for its dependents 78 -- (FATHER and MOTHER) to terminate. FATHER is terminated. 79 80 null; 81<<B4>> end MOTHER; 82 83 begin -- (of TASK_EXAMPLE)(8) 84 -- FATHER is suspended at accept start, and 85 -- CHILD is suspended in its deadlock. 86 -- Mother in suspended state with "Not yet activated" sub state. 87<<B5>> FATHER.START; (9) 88 -- FATHER is suspended at the 'select' or 'terminate' statement. 89 90 91<<B6>> FATHER.RENDEZVOUS; 92 FATHER.RENDEZVOUS; (10) 93 loop (11) 94 -- This loop causes the main program to busy wait for termination of 95 -- FATHER, so that FATHER can be observed in its terminated state. 96 if FATHER'TERMINATED then 97 exit; 98 end if; 99 delay 10.0; -- 10.0 so that MOTHER is suspended 100 end loop; -- at the 'accept' statement (increases determinism). 101 102 -- FATHER has terminated by now with an unhandled 103 -- exception, and CHILD no longer exists because its 104 -- master (FATHER) has terminated. Task MOTHER is ready. 105<<B7>> MOTHER.START; (12) 106 -- The main program enters a wait-for-dependents state 107 -- so that MOTHER can finish executing. 108 end TASK_EXAMPLE; (13) |
目次 | 索引 |
|