| 前へ | 次へ | 目次 | 索引 |
SYNCHRONIZE VECTOR_MODE コマンドを使用する代わりに,SET VECTOR_MODE SYNCHRONIZED コマンドを入力すると,同期化ベクタ・モードでデバッガを稼働することもできます。このコマンドを使用すると,デバッガは,ベクタ命令が実行されるたびに,スカラ型プロセッサとベクタ型プロセッサ間の同期を自動的にとります。また,ベクタ命令を実行するたびにそのあとで SYNC 命令を実行し,さらにメモリにアクセスするベクタ命令を実行したあとで MSYNC 命令を実行します。その結果,次のように同期化の対象となっているベクタ命令に関連したすべての処理が終了します。
次の例は,SET VECTOR_MODE SYNCHRONIZED コマンドを上記の例で使用したのと同じ命令ストリーム上で実行した場合の影響を示しています。
DBG> SHOW VECTOR_MODE Vector mode is nonsynchronized DBG> SET VECTOR_MODE SYNCHRONIZED (1) DBG> SHOW VECTOR_MODE Vector mode is synchronized DBG> STEP (2) stepped to .MAIN.\SUB\%LINE 99 99: VVDIVD V1,V0,V2 DBG> STEP (3) %SYSTEM-F-VARITH, vector arithmetic fault, summary=00000002, mask=00000004, PC=000002E1, PSL=03C00010 break on unhandled exception preceding .MAIN.\SUB\%LINE 100 100: CLRL R0 DBG> |
次の番号は,上記の例の番号に対応しています。
SYNCHRONIZE VECTOR_MODE や SET VECTOR_MODE SYNCHRONIZED のほかにも,同期化に影響を及ぼすデバッガ・コマンド(SET WATCH など)がいくつかあります。
16.9 プログラムのベクタ状態に影響を与えることがある呼び出しルーチン
CALL コマンドとともに /[NO]SAVE_VECTOR_STATE 修飾子を指定すると,ベクタ型プロセッサの現在の状態を保存し,ルーチンが呼び出されたときに復元するかどうかを制御できます。
VAX ベクタ・プロセッサの状態は,次のもので決まります。
CALL コマンドを使用してルーチンを実行すると,ルーチンの実行により,ベクタ・プロセッサの状態が次の動機により変化することがあります。
CALL/SAVE_VECTOR_STATE コマンドは,CALL コマンドを実行する前に存在したベクタ型プロセッサの状態を,呼び出したルーチンの実行が完了したあとにデバッガが復元することを指定します。その結果,呼び出したルーチンの実行が完了したあとに次の各項が確認されます。
CALL/NOSAVE_VECTOR_STATE コマンドは省略時の設定であり,CALL コマンドが実行される前に存在したベクタ型プロセッサの状態は,呼び出したルーチンの実行が完了したあとに復元しないことを指定します。この場合,ルーチン呼び出し後のベクタ型プロセッサの状態は,呼び出したルーチンの影響によって異なります。
/[NO]SAVE_VECTOR_STATE 修飾子は,VAX 汎用(スカラ)レジスタには影響しません。これらのレジスタの値は必ず保存され,CALL コマンドでルーチンを実行すると復元されます。
16.10 画面モードでのベクタ・レジスタ・データの表示
画面モードでは,レジスタ表示が VAX 汎用レジスタの現在の値を示します。第 7.4.5 項 を参照してください。
ベクタ・レジスタまたはベクタ制御レジスタに入っているデータを画面モードで表示するには,DO 表示を使用します。第 7.2.1 項 を参照してください。
たとえば,次のコマンドは,V2_DISP という DO 表示を作成します。これは,レジスタ V2 の要素 4 から 7 までの内容を示します(Fortran 配列構文)。この表示は,プログラムからデバッガに制御が戻るたびに,自動的に更新されます。
DBG> DISPLAY V2_DISP AT RQ2 DO(EXAMINE %V2(4:7)) |
この節では,ベクタ化されたプログラムに対するデバッガのサポートについて,問題と制限事項をまとめます。
DEPOSIT/QUADWORD %VMR = %HEX 0FFFFFFFF |
本章では,タスキング・プログラム(マルチスレッド・プログラムとも呼ぶ)に固有のデバッガ機能について説明します。タスキング・プログラムは 1 つのプロセス内に複数のタスクまたは実行スレッドを持っています。デバッガで使用する タスク という用語は制御の流れのことであり,言語や実現方法とは関係ありません。デバッガのタスキング・サポートは,それらのプログラムすべてに適用されます。次のものを含んでいます。
デバッガの中では,タスクとスレッドという用語は同義語として使われます。 PTHREAD$RTL バージョン 7.1 またはそれ以降のバージョンがリンクされたプログラムをデバッグするときには,PTHREAD コマンドを使って Compaq POSIX Threads デバッガに直接アクセスすることができます。 |
本章では,POSIX Threads 固有か言語固有の情報にはそのことを明記します。第 17.1 節 に POSIX Threads 用語と Ada のタスキング用語の対応表を示します。
本章の機能を使用すれば,次のような処理を行うことができます。
これらの機能を使用するときには,同じタスキング・プログラムを実行してもそのときの状況によっては動作がデバッガにより変更されることがあるので注意してください。たとえば,現在アクティブなタスクの実行をあるブレークポイントで中断しているとき,入出力(I/O)の終了による POSIX 信号か非同期システム・トラップ(AST)が届いた場合は,ユーザの続行指示後ただちにその他のタスクが適格になることがあります。
POSIX Threads や POSIX スレッドについての詳しい説明は,『Guide to POSIX Threads Library』を参照してください。Ada タスクについての詳しい説明は Compaq Ada のマニュアルを参照してください。
マルチプロセス・プログラム(2つ以上のプロセスに分けて実行されるプログラム)のデバッグについては 第 15 章 を参照してください。
17.1 POSIX Threads 用語とAda用語の対応表
表 17-1 に POSIX Threads と Ada の用語とその意味の対応を示します。
| POSIX Threads 用語 | Ada用語 | 意味 |
|---|---|---|
| スレッド | タスク | 同じプロセス内の制御の流れ |
| スレッド・オブジェクト | タスク・オブジェクト | 制御の流れを表すデータ項目 |
| オブジェクト名または式 | タスク名または式 | 制御の流れを表すデータ項目 |
| 開始ルーチン | タスク本体 | 制御の流れに従って実行されるコード |
| 該当なし | 親タスク | 親タスクの制御の流れ |
| 該当なし | 依存タスク | なんらかの親タスクに制御される子タスクの制御の流れ |
| 同期化オブジェクト(ミューテクス,条件変数) | ランデブ構造(エントリ呼び出しやaccept文など) | 制御の流れを同期化する方法 |
| スケジューリング方針およびスケジューリング優先順位 | タスク優先順位 | 実行のスケジューリング方法 |
| 警告処理 | abort文 | 制御の流れの取り消し方法 |
| スレッド状態 | タスク状態 | 実行の状態(待ち,レディ,実行中,終了) |
| スレッド作成属性(優先順位,スケジューリング方針など) | プラグマ | パラレル・エンティティの属性 |
次の各項では,タスキング・プログラムのデバッグ時によく起こるエラーを含んでいるタスキング・プログラムの例を示します。
本章のその他の例は,これらのプログラムを引用したものです。
17.2.1 Cのマルチスレッド・プログラムの例
例 17-1 はマルチスレッドの C のプログラムです。条件変数の使用法が間違っているのでブロッキングを起こします。
例のあとに説明が続いています。その説明のあとに,デバッガを使用してスレッドの相対的な実行を制御することによってブロッキングを診断する方法を示しています。
例 17-1 では,初期スレッドにより,計算作業を行う 2 つのワーカ・スレッドが作成されます。これらのワーカ・スレッドの作成後に SHOW TASK/ALL コマンドを実行すれば,それぞれが 1 つのスレッドに対応する 4 つのタスクが表示されます。第 17.4 節 に SHOW TASK コマンドの使用法が説明されています。
例 17-1 では,ワーカ・スレッドのパスの行 3893 に同期化点(条件待ち)が設けられています。行 3877 から始まるコメントは,このような直接的な呼び出しは間違ったプログラミング方法であることを示したうえで,正しいコーディング方法を示しています。
このプログラムを実行すると,ワーカ・スレッドが大量の計算を行っているときに初期スレッドが条件変数をブロードキャストします。条件変数をモニタしている最初のスレッドは初期スレッドのブロードキャストを検出してクリアし,残りのスレッドを放置します。実行が妨げられ,プログラムは終了できなくなります。
| 例 17-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 }
|
次の番号は,例 17-1 の番号に対応しています。
| 前へ | 次へ | 目次 | 索引 |