スレッドアナライザは、OpenMP 指令、POSIX スレッド、および Solaris スレッドで提供されるほとんどの標準同期 API および構文を認識できます。ただし、このツールはユーザー定義の同期を認識できないため、このような同期を採用した場合、誤検出データ競合が報告される場合があります。たとえば、アセンブリ言語でコードを直接書いて実装したスピンロックは、このツールでは認識できません。
コードにユーザー定義の同期が含まれる場合、この同期を識別するために、スレッドアナライザがサポートするユーザー API をプログラムに挿入します。このように識別することによって、スレッドアナライザは同期を認識でき、誤検知の数を減らすことができます。スレッドアナライザのユーザー API は libtha.so に定義されます。その一覧を次の表に示します。
表 A–1 スレッドアナライザユーザー API
tha_notify_acquire_lock() |
プログラムがユーザー定義のロックを取得しようとする直前に呼び出せます。 |
tha_notify_lock_acquired() |
ユーザー定義のロックが正しく取得された直後に呼び出せます。 |
tha_notify_acquire_writelock() |
プログラムが書き込みモードでユーザー定義の読み取り/書き込みロックを取得しようとする直前に呼び出せます。 |
tha_notify_writelock_acquired() |
書き込みモードでユーザー定義の読み取り/書き込みロックが正しく取得された直後に呼び出せます。 |
tha_notify_acquire_readlock() |
プログラムが読み取りモードでユーザー定義の読み取り/書き込みロックを取得しようとする直前に呼び出せます。 |
tha_notify_readlock_acquired() |
読み取りモードでユーザー定義の読み取り/書き込みロックが正しく取得された直後に呼び出せます。 |
tha_notify_release_lock() |
ユーザー定義のロックまたは読み取り/書き込みロックが解除される直前に呼び出せます。 |
tha_notify_lock_released() |
ユーザー定義のロック (読み取り/書き込みロックを含む) が正しく解除された直後に呼び出せます。 |
tha_notify_sync_post_begin() |
ユーザー定義の送信同期が実行される直前に呼び出せます。 |
tha_notify_sync_post_end() |
ユーザー定義の送信同期が実行された直後に呼び出せます。 |
tha_notify_sync_wait_begin() |
ユーザー定義の待機同期が実行される直前に呼び出せます。 |
tha_notify_sync_wait_end() |
ユーザー定義の待機同期が実行された直後に呼び出せます。 |
C/C++ バージョンと Fortran バージョンの API が用意されています。それぞれの API 呼び出しは単一の引数 ID を取り、その値は同期オブジェクトを一意に識別します。
C/C++ バージョンの API では、引数の型は uintptr_t であり、これは 32 ビットモードでは 4 バイト長、64 ビットモードでは 8 バイト長になります。このバージョンの API を呼び出すときには、#include <tha_interface.h> を C/C++ ソースファイルに追加する必要があります。
Fortran バージョンの API では、引数の型は tha_sobj_kind の整数であり、これは 32 ビットおよび 64 ビットモードで 8 バイト長になります。このバージョンの API を呼び出すときには、#include "tha_finterface.h" を Fortran ソースファイルに追加する必要があります。
同期オブジェクトが一意に識別されるよう、引数の ID には同期オブジェクトごとに異なる値を割り当てる必要があります。これを行う 1 つの方法は、同期オブジェクトのアドレスの値を ID として使用することです。次のコード例では、API を使用して誤検知のデータの競合を回避する方法を示しています。
# include <tha_interface.h> ... /* Initially, the ready_flag value is zero */ ... /* Thread 1: Producer */ 100 data = ... 101 pthread_mutex_lock (&mutex); tha_notify_sync_post_begin ((uintptr_t) &ready_flag); 102 ready_flag = 1; tha_notify_sync_post_end ((uintptr_t) &ready_flag); 103 pthread_cond_signal (&cond); 104 pthread_mutex_unlock (&mutex); /* Thread 2: Consumer */ 200 pthread_mutex_lock (&mutex); tha_notify_sync_wait_begin ((uintptr_t) &ready_flag); 201 while (!ready_flag) { 202 pthread_cond_wait (&cond, &mutex); 203 } tha_notify_sync_wait_end ((uintptr_t) &ready_flag); 204 pthread_mutex_unlock (&mutex); 205 ... = data;
ユーザー API については、libtha(3) のマニュアルページを参照してください。
以降の節では、スレッドアナライザが認識するスレッド API について詳しく説明します。
これらの API については、Oracle Solaris Developer Collection の中の『マルチスレッドのプログラミング』を参照してください。
pthread_mutex_lock() |
pthread_mutex_trylock() |
pthread_mutex_unlock() |
pthread_rwlock_rdlock() |
pthread_rwlock_tryrdlock() |
pthread_rwlock_wrlock() |
pthread_rwlock_trywrlock() |
pthread_rwlock_unlock() |
pthread_create() |
pthread_join() |
pthread_cond_signal() |
pthread_cond_broadcast() |
pthread_cond_wait() |
pthread_cond_timedwait() |
pthread_cond_reltimedwait_np() |
pthread_barrier_init() |
pthread_barrier_wait() |
pthread_spin_lock() |
pthread_spin_unlock() |
pthread_spin_trylock() |
pthread_mutex_timedlock() |
pthread_mutex_reltimedlock_np() |
pthread_rwlock_timedrdlock() |
pthread_rwlock_reltimedrdlock_np() |
pthread_rwlock_timedwrlock() |
pthread_rwlock_reltimedwrlock_np() |
sem_post() |
sem_wait() |
sem_trywait() |
sem_timedwait() |
sem_reltimedwait_np() |
これらの API については、Oracle Solaris Developer Collection の中の『マルチスレッドのプログラミング』を参照してください。
mutex_lock() |
mutex_trylock() |
mutex_unlock() |
rw_rdlock() |
rw_tryrdlock() |
rw_wrlock() |
rw_trywrlock() |
rw_unlock() |
thr_create() |
thr_join() |
cond_signal() |
cond_broadcast() |
cond_wait() |
cond_timedwait() |
cond_reltimedwait() |
sema_post() |
sema_wait() |
sema_trywait() |
calloc() |
malloc() |
realloc() |
valloc() |
memalign() |
メモリー割り当て API については、malloc(3C) のマニュアルページを参照してください。
memcpy() |
memmove() |
memchr() |
memcmp() |
memset() |
メモリー操作 API については、memcpy(3C) のマニュアルページを参照してください。
strcat() |
strncat() |
strlcat() |
strcasecmp() |
strncasecmp() |
strchr() |
strrchr() |
strcmp() |
strncmp() |
strcpy() |
strncpy() |
strlcpy() |
strcspn() |
strspn() |
strdup() |
strlen() |
strpbrk() |
strstr() |
strtok() |
文字列操作 API については、strcat(3C) のマニュアルページを参照してください。
スレッドアナライザは、バリアー、ロック、クリティカル領域、不可分 (アトミック) 領域、taskwait などの OpenMP 同期を認識します。
詳細は、『Oracle Solaris Studio 12.2: OpenMP API ユーザーガイド』を参照してください。