JavaScript is required to for searching.
ナビゲーションリンクをスキップ
印刷ビューの終了
Oracle Solaris Studio 12.3: スレッドアナライザユーザーズガイド     Oracle Solaris Studio 12.3 Information Library (日本語)
search filter icon
search icon

ドキュメントの情報

はじめに

1.  スレッドアナライザとその機能について

2.  データの競合チュートリアル

2.1 データの競合チュートリアルのソースファイル

2.1.1 データの競合チュートリアルのソースファイルの入手

2.1.2 prime_omp.c のソースコード

2.1.3 prime_pthr.c のソースコード

2.1.3.1 prime_omp.c および prime_pthr.c でのデータの競合の影響

2.2 スレッドアナライザを使用したデータの競合の検出方法

2.2.1 コードを計測する

2.2.1.1 ソースコードを計測する

2.2.1.2 バイナリコードを計測する

2.2.2 データの競合の検出実験を作成する

2.2.3 データの競合の検出実験を検証する

2.2.3.1 スレッドアナライザを使用したデータの競合実験の表示

2.2.3.2 er_print を使用したデータの競合実験の表示

2.3 実験結果について

2.3.1 prime_omp.c でのデータの競合

2.3.2 prime_pthr.c でのデータの競合

2.3.3 データの競合の呼び出しスタックトレース

2.4 データの競合の原因の診断

2.4.1 データの競合が誤検知であるかどうかをチェックする

2.4.2 データの競合が影響のないものであるかどうかを確認する

2.4.3 データの競合ではなくバグを修正する

2.4.3.1 prime_omp.c でのバグの修正

2.4.3.2 prime_pthr.c でのバグの修正

2.5 誤検知

2.5.1 ユーザー定義の同期

2.5.2 さまざまなスレッドでリサイクルされるメモリー

2.6 影響のないデータの競合

2.6.1 素数検索用のプログラム

2.6.2 配列値の型を検証するプログラム

2.6.3 二重検査されたロックを使用したプログラム

3.  デッドロックのチュートリアル

A.  スレッドアナライザで認識される API

B.  役に立つヒント

2.5 誤検知

スレッドアナライザは、実際にはプログラム内で生じていないデータの競合を報告する場合があります。これらは誤検知と呼ばれます。ほとんどの場合、誤検知は、ユーザー定義の同期によって、またはさまざまなスレッドでリサイクルされるメモリーによって引き起こされます。詳しくは、「2.5.1 ユーザー定義の同期」および「2.5.2 さまざまなスレッドでリサイクルされるメモリー」を参照してください。

2.5.1 ユーザー定義の同期

スレッドアナライザは、OpenMP、POSIX スレッド、および Solaris スレッドで提供されるほとんどの標準同期 API と構文を認識できます。ただし、ツールはユーザー定義の同期を認識できず、このような同期がコードに含まれる場合、誤検知のデータの競合を報告することがあります。


注 - このような誤検知のデータの競合を報告しないようにするために、スレッドアナライザには、ユーザー定義の同期が実行されたときにツールに通知するために使用できる一連の API が用意されています。詳しくは、「A.1 スレッドアナライザユーザー API」 を参照してください。


なぜ API を使用する必要があるかを説明するため、次のように考えてみましょう。スレッドアナライザは、CAS 命令を使用したロックの実装、ビジー待機を使用した送信および待機操作などを認識できません。次に、プログラムが POSIX スレッド状態変数の一般的な使用法を採用した、誤検知のクラスの一般的な例を示します。

/* Initially ready_flag is 0 */
 
/* Thread 1: Producer */
100   data = ...
101   pthread_mutex_lock (&mutex);  
102   ready_flag = 1;
103   pthread_cond_signal (&cond);
104   pthread_mutex_unlock (&mutex);
...
/* Thread 2: Consumer */
200   pthread_mutex_lock (&mutex);
201   while (!ready_flag) {
202       pthread_cond_wait (&cond, &mutex);   
203   }
204   pthread_mutex_unlock (&mutex);
205   ... = data;

pthread_cond_wait() 呼び出しは、通常、プログラムエラーと疑わしいウェイクアップから保護するために述語をテストするループ内で行われます。述語のテストおよび設定は、多くの場合、相互排他ロックによって保護されます。前述のコードでは、スレッド 1 は行 100 で変数 data の値を生成し、行 102 で ready_flag の値を 1 に設定してデータが生成されていることを示します。続いて、 pthread_cond_signal() を呼び出して、消費者スレッドであるスレッド 2 を呼び起こします。スレッド 2 はループ内の述語 (!ready_flag) をテストします。フラグが設定されていることを検出すると、行 205 でデータを消費します。

行 102 での ready_flag の書き込みと行 201 での ready_flag の読み取りは、同じ相互排他ロックで保護されています。したがって、2 つのアクセス間にデータの競合はなく、ツールは正しく認識します。

行 100 での data の書き込みと、行 205 での data の読み取りは、相互排他ロックによって保護されません。ただし、プログラムロジックでは、フラグ変数 ready_flag のために行 205 での読み取りは常に、行 100 での書き込み後に行われます。この結果、データへのこれら 2 つのアクセス間にデータの競合は生じません。ただし、pthread_cond_wait() の呼び出し (行 202) が実際には実行時に呼び出されない場合、ツールは、2 つのアクセス間でデータの競合があると報告します。行 201 が実行される前に行 102 が実行された場合は、行 201 が実行されると、ループエントリテストは失敗し、行 202 はスキップされます。ツールは pthread_cond_signal() 呼び出しおよび pthread_cond_wait() 呼び出しを監視し、それらを組み合わせて同期を派生できます。行 202 で pthread_cond_wait() が呼び出されない場合、行 100 での書き込みが常に行 205 の読み取り前に実行されることがツールにはわかりません。したがって、これらが同時に実行されていると見なし、これらの間でデータの競合が生じていると報告します。

libtha(3C) のマニュアルページと「A.1 スレッドアナライザユーザー API」 では、API を使用して、このような誤検知のデータの競合を報告しないようにする方法について説明しています。

2.5.2 さまざまなスレッドでリサイクルされるメモリー

一部のメモリー管理ルーチンは、あるスレッドが別のスレッドで使用できるように解放したメモリーをリサイクルします。スレッドアナライザは、別々のスレッドが使用する同じメモリー位置の寿命が重複していないことを認識できない場合があります。これが起きたときに、ツールは誤検知のデータの競合を報告することがあります。次の例は、この種の誤検知を示しています。

/*----------*/                    /*----------*/
/* Thread 1 */                    /* Thread 2 */
/*----------*/                    /*----------*/
 ptr1 = mymalloc(sizeof(data_t));
 ptr1->data = ...
 ...
 myfree(ptr1);

                                  ptr2 = mymalloc(sizeof(data_t));
                                  ptr2->data = ...
                                  ...
                                  myfree(ptr2);

スレッド 1 とスレッド 2 は同時に実行します。各スレッドは、プライベートメモリーに使用されるメモリーのチャンクを割り当てます。ルーチン mymalloc() は、myfree() の以前の呼び出しによって解放されたメモリーを提供できます。スレッド 2 は、スレッド 1 が myfree() を呼び出す前に、mymalloc() を呼び出します。この場合、ptr1ptr2 は別々の値を取り、2 つのスレッド間でデータの競合は生じません。ただし、スレッド 1 が myfree () を呼び出した後にスレッド 2 が mymalloc() を呼び出した場合、ptr1ptr2 が同じ値を取ることがあります。スレッド 1 はこのメモリーにアクセスできなくなるので、データの競合は生じません。ただし、mymalloc() がメモリーをリサイクルしていることがわかっていない場合、ツールは、ptr1 データの書き込みと ptr2 データの書き込みとのデータの競合を報告します。この種の誤検知は、多くの場合、C++ アプリケーションで、C++ 実行時ライブラリがメモリーを一時変数用にリサイクルするときに起こりますまたしばしば、独自のメモリー管理ルーチンを実装したユーザーアプリケーションでも起こります。現在、スレッドアナライザは、標準の malloc()calloc()、および realloc() インタフェースで実行されたメモリー割り当ておよび解放操作を認識できます。