library home hp.com home products and services support and drivers solutions
cd-rom home
End of Jump to page title
HP OpenVMS Systems
Documentation

Jump to content


HP OpenVMS

HP OpenVMS
デバッガ説明書


前へ 次へ 目次 索引


15.16.6 デバッグのシステム要件

複数のユーザが同時にプログラムをデバッグすると,システムに負荷がかかります。本項では,デバッガが使用するリソースについて説明し,ユーザやシステム管理者が,プログラムのデバッグ作業用にシステムを調整できるようにします。

ここでは,デバッガが使用するリソースだけについて説明します。プログラム自体をサポートするには,システムを調整しなくてはならない場合もあります。

15.16.6.1 ユーザ・クォータ

各ユーザは,デバッガ用の追加プロセスを作成するために十分な PRCLM クォータを必要とします。このとき,プログラムの実行に必要な数以上のプロセスを作成できるようにします。

BYTLM,ENQLM,FILLM,および PGFLQUOTA は,プール・クォータです。これらのクォータは,デバッガ・プロセスを考慮して,次のように増やさなければならないに場合があります。

15.16.6.2 システム・リソース

カーネル・デバッガとメイン・デバッガはグローバル・セクションを通して通信を行います。個々のメイン・デバッガは,プラットフォームに関係なく,少なくとも 64 KB のグローバル・セクションを 1 つ使用します。 VAX と Alpha では,メイン・デバッガは,最大 6 個のカーネル・デバッガと通信できます。 I64 では,メイン・デバッガが通信できるカーネル・デバッガの数は,最大 2 個までです。

15.17 例

例 15-4例 15-5 は,本章の例で使用しているサーバ・プログラムとクライアント・プログラムの C のコードを示しています。

例 15-4 server.c

#include <stdio.h> 
#include <starlet.h> 
#include <cmbdef.h> 
#include <types.h> 
#include <descrip.h> 
#include <efndef.h> 
#include <iodef.h> 
#include <iosbdef.h> 
#include <ssdef.h> 
#include <string.h> 
 
#include "mbxtest.h" 
 
int main (int argc, char **argv) 
{ 
    unsigned int status, write_ef; 
    char line_buf [LINE_MAX_LEN + 1]; 
    iosb myiosb; 
    short mbxchan; 
 
    /* Get event flag.  Look for or create the mailbox. 
     */ 
    status = lib$get_ef (&write_ef); 
    if (!(status & 1)) 
    { 
 fprintf (stderr, "Server unable to get eventflag, 
                                  status = %x", status); 
 return 0; 
    } 
    status = sys$crembx (0, &mbxchan, 0, 0, 0, 0, &mbxname_dsc, 
                                  CMB$M_WRITEONLY, 0); 
    if (!(status & 1)) 
    { 
 fprintf (stderr, "Server unable to open mailbox, 
                                  status = %x", status); 
 return 0; 
    } 
 
    /* Open for business.  Loop looking for and processing requests. 
     */ 
    while (TRUE) 
    { 
 printf ("Input command: "); 
 gets (&line_buf); 
 
 status = sys$clref (write_ef); 
 if (!(status & 1)) 
 { 
     fprintf (stderr, "Client unable to clear read event flag, 
                                  status = %x", status); 
     return 0; 
 } 
 status = sys$qiow (write_ef, mbxchan, 
                                  IO$_SETMODE | IO$M_READERWAIT, &myiosb, 
                           0, 0, 0, 0, 0, 0, 0, 0); 
 
 if ((status) && (myiosb.iosb$w_status)) 
 { 
     status = sys$clref (write_ef); 
     if (!(status & 1)) 
     { 
  fprintf (stderr, "Client unable to clear read event flag, 
                                  status = %x", status); 
  return 0; 
     } 
     if (strlen (line_buf) == 0) 
  status = sys$qio (write_ef, mbxchan, IO$_WRITEOF | IO$M_READERCHECK, &myiosb, 
              0, 0, 0, 0, 0, 0, 0, 0); 
     else 
  status = sys$qio (write_ef, mbxchan, IO$_WRITEVBLK | IO$M_READERCHECK, &myiosb, 
              0, 0, line_buf, strlen (line_buf), 0, 0, 0, 0); 
     if (status) 
     { 
  status = sys$waitfr (write_ef); 
  if ((myiosb.iosb$w_status & 1) && (status & 1)) 
                { 
      if (strlen (line_buf) == 0) 
   break; 
  } 
  else 
      fprintf (stderr, "Server failure during write, 
                             status = %x, iosb$w_status = %x\n", 
               status, myiosb.iosb$w_status); 
     } 
     else 
  fprintf (stderr, "Server failure for write request, 
                             status = %x\n", status); 
 } 
 else 
     fprintf (stderr, "Server failure during wait for reader, 
                             status = %x, iosb$w_status = %x\n", 
               status, myiosb.iosb$w_status);  
    } 
    printf ("\n\nServer done...exiting\n"); 
    return 1; 
} 

例 15-5 client.c

#include <stdio.h> 
#include <starlet.h> 
#include <cmbdef.h> 
#include <types.h> 
#include <descrip.h> 
#include <efndef.h> 
#include <iodef.h> 
#include <iosbdef.h> 
#include <ssdef.h> 
#include <string.h> 
 
#include "mbxtest.h" 
 
int main (int argc, char **argv) 
{ 
    unsigned int status, read_ef; 
    iosb myiosb; 
    short mbxchan; 
    char line_buf [LINE_MAX_LEN]; 
 
    /* Get event flag.  Look for or create the mailbox. 
     */ 
    status = lib$get_ef (&read_ef); 
 
    if (!(status & 1)) 
    { 
 fprintf (stderr, "Client unable to get eventflag, status = %x", status); 
 return 0; 
    } 
    status = sys$crembx (0, &mbxchan, 0, 0, 0, 0, &mbxname_dsc, CMB$M_READONLY, 0); 
    if (!(status & 1)) 
    { 
 fprintf (stderr, "Client unable to open mailbox, status = %x", status); 
 return 0; 
    } 
 
    /* Loop requesting, receiving, and processing new data. 
     */ 
    memset (&myiosb, 0, sizeof(myiosb)); 
 
    while (myiosb.iosb$w_status != SS$_ENDOFFILE) 
    { 
 status = sys$qiow (read_ef, mbxchan, IO$_SETMODE | IO$M_WRITERWAIT, &myiosb, 
      0, 0, 0, 0, 0, 0, 0, 0); 
 if ((status) && (myiosb.iosb$w_status)) 
 { 
     status = sys$clref (read_ef); 
     if (!(status & 1)) 
     { 
  fprintf (stderr, "Client unable to clear read event flag, status = %x", status); 
  return 0; 
     } 
     status = sys$qio (read_ef, mbxchan, IO$_READVBLK | IO$M_WRITERCHECK, &myiosb, 
          0, 0, line_buf, sizeof(line_buf), 0, 0, 0, 0); 
     if (status) 
     { 
  status = sys$waitfr (read_ef); 
  if ((myiosb.iosb$w_status & 1) && (status & 1)) 
      puts (line_buf); 
  else if ((myiosb.iosb$w_status != SS$_NOWRITER) && 
                             (myiosb.iosb$w_status != SS$_ENDOFFILE)) 
      fprintf (stderr, "Client failure during read, 
                             status = %x, iosb$w_status = %x\n", 
               status, myiosb.iosb$w_status); 
     } 
     else 
  fprintf (stderr, "Client failure for read request, status = %x\n", status); 
 } 
 else 
     fprintf (stderr, "Client failure during wait for writer, 
                             status = %x, iosb$w_status = %x\n", 
               status, myiosb.iosb$w_status); 
 status = sys$clref (read_ef); 
 if (!(status & 1)) 
 { 
     fprintf (stderr, "Client unable to clear read event flag, 
                             status = %x", status); 
     return 0; 
 } 
    } 
    printf ("\nClient done...exiting\n"); 
    return 1; 
} 

例 15-4 および 例 15-5 に含まれるヘッダ・ファイル mbxtest.h は,以下のように表示されます。


$DESCRIPTOR(mbxname_dsc, "dbg$mptest_mbx"); 
 
#define LINE_MAX_LEN 255                 


第 16 章
タスキング・プログラムのデバッグ

本章では,タスキング・プログラム ( マルチスレッド・プログラムとも呼ぶ ) に固有のデバッガ機能について説明します。タスキング・プログラムは 1 つのプロセス内に複数のタスクまたは実行スレッドを持っています。デバッガで使用する タスク という用語は制御の流れのことであり,言語や実現方法とは関係ありません。デバッガのタスキング・サポートは,それらのプログラムすべてに適用されます。次のものを含んでいます。

注意

デバッガの中では,タスクとスレッドという用語は同義語として使われます。

PTHREAD$RTL バージョン 7.1 またはそれ以降のバージョンがリンクされたプログラムをデバッグするときには,PTHREAD コマンドを使って Compaq POSIX Threads デバッガに直接アクセスすることができます。

本章では, POSIX Threads 固有か言語固有の情報にはそのことを明記します。 第 16.1 節 に POSIX Threads 用語と Ada のタスキング用語の対応表を示します。

本章の機能を使用すれば,次のような処理を行うことができます。

これらの機能を使用するときには,同じタスキング・プログラムを実行してもそのときの状況によっては動作がデバッガにより変更されることがあるので注意してください。たとえば,現在アクティブなタスクの実行をあるブレークポイントで中断しているとき,入出力 (I/O) の終了による POSIX 信号か非同期システム・トラップ (AST) が届いた場合は,ユーザの続行指示後ただちにその他のタスクが適格になることがあります。

POSIX Threads についての詳しい説明は,『Guide to the POSIX Threads Library』を参照してください。 Ada タスクについての詳しい説明は Compaq Ada のマニュアルを参照してください。

マルチプロセス・プログラム(2つ以上のプロセスに分けて実行されるプログラム)のデバッグについては 第 15 章 を参照してください。

16.1 POSIX Threads 用語とAda用語の対応表

表 16-1 に POSIX Threads と Ada の用語とその意味の対応を示します。

表 16-1 POSIX Threads用語と Ada 用語の対応
POSIX Threads 用語 Ada用語 意味
スレッド タスク 同じプロセス内の制御の流れ
スレッド・オブジェクト タスク・オブジェクト 制御の流れを表すデータ項目
オブジェクト名または式 タスク名または式 制御の流れを表すデータ項目
開始ルーチン タスク本体 制御の流れに従って実行されるコード
該当なし 親タスク 親タスクの制御の流れ
該当なし 依存タスク なんらかの親タスクに制御される子タスクの制御の流れ
同期化オブジェクト(ミューテクス,条件変数) ランデブ構造 ( エントリ呼び出しやaccept文など ) 制御の流れを同期化する方法
スケジューリング方針およびスケジューリング優先順位 タスク優先順位 実行のスケジューリング方法
警告処理 abort文 制御の流れの取り消し方法
スレッド状態 タスク状態 実行の状態 ( 待ち,レディ,実行中,終了)
スレッド作成属性 ( 優先順位,スケジューリング方針など ) プラグマ パラレル・エンティティの属性

16.2 タスキング・プログラムの例

次の各項では,タスキング・プログラムのデバッグ時によく起こるエラーを含んでいるタスキング・プログラムの例を示します。

本章のその他の例は,これらのプログラムを引用したものです。

16.2.1 Cのマルチスレッド・プログラムの例

例 16-1 はマルチスレッドの C のプログラムです。条件変数の使用法が間違っているのでブロッキングを起こします。

例のあとに説明が続いています。その説明のあとに,デバッガを使用してスレッドの相対的な実行を制御することによってブロッキングを診断する方法を示しています。

例 16-1 では,初期スレッドにより,計算作業を行う 2 つのワーカ・スレッドが作成されます。これらのワーカ・スレッドの作成後に SHOW TASK/ALL コマンドを実行すれば,それぞれが 1 つのスレッドに対応する 4 つのタスクが表示されます。 第 16.4 節 に SHOW TASK コマンドの使用法が説明されています。

例 16-1 では,ワーカ・スレッドのパスの行 3893 に同期化点 ( 条件待ち ) が設けられています。行 3877 から始まるコメントは,このような直接的な呼び出しは間違ったプログラミング方法であることを示したうえで,正しいコーディング方法を示しています。

このプログラムを実行すると,ワーカ・スレッドが大量の計算を行っているときに初期スレッドが条件変数をブロードキャストします。条件変数をモニタしている最初のスレッドは初期スレッドのブロードキャストを検出してクリアし,残りのスレッドを放置します。実行が妨げられ,プログラムは終了できなくなります。

例 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 の番号に対応しています。


前へ 次へ 目次 索引