スレッドアナライザで認識される API
スレッドアナライザは、OpenMP、POSIX スレッド、および Solaris スレッドで提供されるほとんどの標準同期 API と構文を認識できます。ただし、このツールはユーザー定義の同期を認識できないため、このような同期を採用した場合、誤検知のデータ競合が報告される場合があります。たとえば、アセンブリ言語でコードを直接書いて実装したスピンロックは、このツールでは認識できません。
スレッドアナライザユーザー 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()
|
ユーザー定義の待機同期が実行された直後に呼び出せます。
|
tha_check_datarace_mem()
|
このルーチンは、データの競合の検出の実行中に、指定されたメモリーブロックへのアクセスをモニターまたは無視するようスレッドアナライザに指示します。
|
tha_check_datarace_thr()
|
このルーチンは、データの競合の検出の実行中に、1 つ以上のスレッドによるメモリーアクセスをモニターまたは無視するようスレッドアナライザに指示します。
|
|
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 を使用して誤検出データ競合を回避する方法を示しています。
使用例 A-1 スレッドアナライザ 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 について詳しく説明します。
POSIX スレッド API
これらの API については、Oracle Solaris ドキュメントのマルチスレッドのプログラミングを参照してください。
| pthread_detach() | | pthread_mutex_init() | | pthread_mutex_lock() | | pthread_mutex_timedlock() | | pthread_mutex_reltimedlock_np() | | pthread_mutex_timedlock() | | 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_rwlock_init() | | 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() |
|
Oracle Solaris スレッド API
これらの API については、Oracle Solaris ドキュメントのマルチスレッドのプログラミングを参照してください。
| mutex_init() | | mutex_lock() | | mutex_trylock() | | mutex_unlock() | | rw_rdlock() | | rw_tryrdlock() | | rw_wrlock() | | rw_trywrlock() | | rw_unlock() | | rwlock_init() | | thr_create() | | thr_join() | | cond_signal() | | cond_broadcast() | | cond_wait() | | cond_timedwait() | | cond_reltimedwait() | | sema_post() | | sema_wait() | | sema_trywait() |
|
メモリー割り当て API
| calloc() | | malloc() | | realloc() | | valloc() | | memalign() | | free() |
|
メモリー割り当て API については、malloc(3C) のマニュアルページを参照してください。
メモリー操作 API
| memcpy() | | memccpy() | | memmove() | | memchr() | | memcmp() | | memset() |
|
メモリー操作 API については、memcpy(3C) のマニュアルページを参照してください。
文字列操作 API
| strcat() | | strncat() | | strlcat() | | strcasecmp() | | strncasecmp() | | strchr() | | strrchr() | | strcmp() | | strncmp() | | strcpy() | | strncpy() | | strlcpy() | | strcspn() | | strspn() | | strdup() | | strlen() | | strpbrk() | | strstr() | | strtok() |
|
文字列操作 API については、strcat(3C) のマニュアルページを参照してください。
リアルタイムライブラリ API
| sem_post() | | sem_wait() | | sem_trywait() | | sem_timedwait() |
|
不可分動作 (atomic_ops) API
| atomic_add() | | atomic_and() | | atomic_cas() | | atomic_dec() | | atomic_inc() | | atomic_or() | | atomic_swap() |
|
OpenMP API
スレッドアナライザは、バリアー、ロック、クリティカル領域、不可分 (アトミック) 領域、taskwait などの OpenMP 同期を認識します。
詳細は、Oracle Solaris Studio 12.4: OpenMP API ユーザーズガイド
を参照してください。