HP OpenVMS Systems Documentation |
| 前へ | 次へ | 目次 | 索引 |
複数のユーザが同時にプログラムをデバッグすると,システムに負荷がかかります。本項では,デバッガが使用するリソースについて説明し,ユーザやシステム管理者が,プログラムのデバッグ作業用にシステムを調整できるようにします。
ここでは,デバッガが使用するリソースだけについて説明します。プログラム自体をサポートするには,システムを調整しなくてはならない場合もあります。
15.16.6.1 ユーザ・クォータ
各ユーザは,デバッガ用の追加プロセスを作成するために十分な PRCLM クォータを必要とします。このとき,プログラムの実行に必要な数以上のプロセスを作成できるようにします。
BYTLM,ENQLM,FILLM,および PGFLQUOTA は,プール・クォータです。これらのクォータは,デバッガ・プロセスを考慮して,次のように増やさなければならないに場合があります。
カーネル・デバッガとメイン・デバッガはグローバル・セクションを通して通信を行います。個々のメイン・デバッガは,プラットフォームに関係なく,少なくとも 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 |
本章では,タスキング・プログラム ( マルチスレッド・プログラムとも呼ぶ ) に固有のデバッガ機能について説明します。タスキング・プログラムは 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 の用語とその意味の対応を示します。
| POSIX Threads 用語 | Ada用語 | 意味 |
|---|---|---|
| スレッド | タスク | 同じプロセス内の制御の流れ |
| スレッド・オブジェクト | タスク・オブジェクト | 制御の流れを表すデータ項目 |
| オブジェクト名または式 | タスク名または式 | 制御の流れを表すデータ項目 |
| 開始ルーチン | タスク本体 | 制御の流れに従って実行されるコード |
| 該当なし | 親タスク | 親タスクの制御の流れ |
| 該当なし | 依存タスク | なんらかの親タスクに制御される子タスクの制御の流れ |
| 同期化オブジェクト(ミューテクス,条件変数) | ランデブ構造 ( エントリ呼び出しやaccept文など ) | 制御の流れを同期化する方法 |
| スケジューリング方針およびスケジューリング優先順位 | タスク優先順位 | 実行のスケジューリング方法 |
| 警告処理 | abort文 | 制御の流れの取り消し方法 |
| スレッド状態 | タスク状態 | 実行の状態 ( 待ち,レディ,実行中,終了) |
| スレッド作成属性 ( 優先順位,スケジューリング方針など ) | プラグマ | パラレル・エンティティの属性 |
次の各項では,タスキング・プログラムのデバッグ時によく起こるエラーを含んでいるタスキング・プログラムの例を示します。
本章のその他の例は,これらのプログラムを引用したものです。
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 の番号に対応しています。
| 前へ | 次へ | 目次 | 索引 |