线程分析器可以识别由 OpenMP 指令、POSIX 线程和 Solaris 线程提供的大多数标准同步 API 和构造。但是,该工具无法识别用户自定义的同步,如果使用了这样的同步,可能会误报数据争用。例如,该工具无法识别通过手编汇编语言代码实现的自旋锁。
如果代码包含用户自定义的同步,请将线程分析器支持的用户 API 插入该程序中来标识这些同步。通过此标识,线程分析器可识别这些同步并减少误报的数量。下面列出了在 libtha.so 中定义的线程分析器用户 API。
表 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 应具有不同的值。其中一种做法是将同步对象的地址值用作 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 开发者文档集的《多线程编程指南》。
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 开发者文档集的《多线程编程指南》。
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) 手册页。
线程分析器可识别 OpenMP 同步,例如屏障、锁、临界区域、原子区域和任务等待 (taskwait)。
有关更多信息,请参见《Oracle Solaris Studio 12.2:OpenMP API 用户指南》。