Oracle Solaris Studio 12.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 を使用して、このような誤検知のデータの競合を報告しないようにする方法について説明しています。