| 日本-日本語 | 
      
  | 
  
      
  | 
  
| 
 | 
     
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)  | 
| 目次 | 索引 | 
      
  | 
  ||||||||