cc [options ] file -Linstall_path/lib -Rinstall_path/lib -ltha CC [ options ] file -ltha #include "tha_interface.h" void tha_notify_acquire_lock (uintptr_t id);
void tha_notify_lock_acquired (uintptr_t id);
void tha_notify_acquire_writelock (uintptr_t id);
void tha_notify_writelock_acquired (uintptr_t id);
void tha_notify_acquire_readlock (uintptr_t id);
void tha_notify_readlock_acquired (uintptr_t id);
void tha_notify_release_lock (uintptr_t id);
void tha_notify_lock_released (uintptr_t id);
void tha_notify_sync_post_begin (uintptr_t id);
void tha_notify_sync_post_end (uintptr_t id);
void tha_notify_sync_wait_begin (uintptr_t id);
void tha_notify_sync_wait_end (uintptr_t id);
void tha_check_datarace_mem (uintptr_t addr, size_t size, int onoff);
void tha_check_datarace_thr (int selfall, int onoff);
f95 [ options ] file -ltha include "tha_finterface.h" subroutine tha_notify_acquire_lock (id) integer(kind=tha_sobj_kind) :: id subroutine tha_notify_lock_acquired (id) integer(kind=tha_sobj_kind) :: id subroutine tha_notify_acquire_writelock (id) integer(kind=tha_sobj_kind) :: id subroutine tha_notify_writelock_acquired (id) integer(kind=tha_sobj_kind) :: id subroutine tha_notify_acquire_readlock (id) integer(kind=tha_sobj_kind) :: id subroutine tha_notify_readlock_acquired (id) integer(kind=tha_sobj_kind) :: id subroutine tha_notify_release_lock (id) integer(kind=tha_sobj_kind) :: id subroutine tha_notify_lock_released (id) integer(kind=tha_sobj_kind) :: id subroutine tha_notify_sync_post_begin (id) integer(kind=tha_sobj_kind) :: id subroutine tha_notify_sync_post_end (id) integer(kind=tha_sobj_kind) :: id subroutine tha_notify_sync_wait_begin (id) integer(kind=tha_sobj_kind) :: id subroutine tha_notify_sync_wait_end (id) integer(kind=tha_sobj_kind) :: id subroutine tha_check_datarace_mem (addr, mem_size, onoff) integer(kind=tha_sobj_kind), intent(in) :: addr integer(kind=4), intent(in) :: mem_size integer(kind=4), intent(in) :: onoff subroutine tha_check_datarace_thr (selfall, onoff) integer(kind=4), intent(in) :: selfall integer(kind=4), intent(in) :: onoff
共享对象 libtha.so 提供了可与 Oracle Solaris Studio 线程分析器结合使用的 API。API 例程可用于通知线程分析器同步或控制数据争用检测。
请注意,libtha.so 仅为 API 例程提供“挂接”(或哑元)入口点。这样,调用这些例程的程序以及与 libtha.so 链接的程序既能在线程分析器实验外部运行,也能在此类实验内部运行。
如果程序在线程分析器实验外部运行(即,程序既不在 collect -r race 下运行,也不在 collect -r deadlock 下运行),则 API 例程将不起任何作用。
如果程序在线程分析器实验下运行(即,程序在 collect -r race 或 collect -r deadlock 下运行),则例程会起作用。
有关执行线程分析器实验的更多信息,请参见 collect(1)。
线程分析器可以识别由 OpenMP、POSIX 线程和 Solaris 线程提供的大多数标准同步 API 和构造。但是,该工具无法识别自行开发样式的同步,如果使用这样的同步,可能会误报数据争用。例如,该工具无法识别使用手编汇编实现的自旋锁。
如果程序包括自行开发样式的同步,则可以在程序中插入对 libtha.so API 的调用,以通知线程分析器这些同步。通过这些调用,该工具可识别同步,从而减少误报数据争用的数量。
libtha.so 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++ 版本的 libtha API 中,上述每个例程都采用单个参数 id,其值应该唯一标识同步对象。id 的类型为 uintptr_t,是在 <sys/types.h> 中定义的。在 32 位模式下,id 的大小为 4 字节;在 64 位模式下,其大小为 8 字节。
在 Fortran 版本的 libtha API 中,上述每个例程都采用单个参数 id,其值应该唯一标识同步对象。id 的类型为整数,其大小由 tha_sobj_kind 指定,在 tha_finterface.h 中将其定义为在 32 位和 64 位模式下都是 8 字节。
为了唯一标识同步对象,对于每个不同的同步对象,应确保参数 id 具有不同的值。要做到这一点,一种方法是让 id 的值作为同步对象的地址。在 C/C++ 中,可以使用 & 运算符获取该地址;在 Fortran 中,可以使用 loc() 库例程获取该地址。请参见下文“示例”部分下的示例 1。
您可以在程序中插入对 libtha.so API 的调用来控制数据争用检测。
tha_check_datarace_mem():该例程指示线程分析器在执行数据争用检测时监视或忽略对指定内存块的访问。当 onoff 参数是 THA_CHK_OFF 时,将禁用对指定内存块的数据争用检测。当 onoff 参数是 THA_CHK_ON, 时,将启用对指定内存块的数据争用检测。当 onoff 既不是 THA_CHK_OFF 也不是 THA_CHK_ON 时,调用的行为未定义。内存块从 addr 开始,包含 size 字节。当 addr 为 NULL 且 size 为零时,将内存块视为所有内存。缺省情况下,当启用了数据争用检测时,线程分析器将监视所有内存访问。请注意,如果影响同一内存块的多个调用由不同线程执行,则调用以线程分析器收到它们的顺序起作用。您可能希望正确同步这些调用。当未通过 collect (1) 命令启用数据争用检测时,对该例程的调用不起任何作用。
tha_check_datarace_thr():该例程指示线程分析器在执行数据争用检测时监视或忽略一个或多个特定线程进行的内存访问。当 onoff 参数是 THA_CHK_OFF 时,将禁用对指定线程的数据争用检测。当 onoff 参数是 THA_CHK_ON 时,将启用对指定线程的数据争用检测。当 onoff 既不是 THA_CHK_OFF 也不是 THA_CHK_ON 时,调用的行为未定义。当 selfall 参数是 THA_CHK_THR_SELF 时,它仅影响正在调用的线程(即,仅启用/禁用对正在调用的线程的数据争用检测)。当 selfall 参数是 THA_CHK_THR_ALL 时,它影响所有线程,包括在该调用后创建的新线程(即,为所有线程禁用数据争用检测)。当 selfall 参数既不是 THA_CHK_THR_SELF 也不是 THA_CHK_THR_ALL 时,调用的行为未定义。缺省情况下,当启用了数据争用检测时,线程分析器将监视所有线程。请注意,如果影响同一线程的多个调用由不同线程执行,则调用以线程分析器收到它们的顺序起作用。您可能希望正确同步这些调用。当未通过 collect (1) 命令启用数据争用检测时,对该例程的调用不起任何作用。
请参见下文“示例”部分下的示例 3 和示例 4。
示例 1:
以下 Fortran 示例显示了如何分别使用 tha_notify_acquire_lock() 和 tha_notify_release_lock() 通知线程分析器用户定义的锁已获取和已释放。在本示例中,锁定对象的地址用作 id 来唯一标识对象。
include "tha_finterface.h" integer :: my_lock integer(kind= tha_sobj_kind) :: id id = loc (my_lock) tha_notify_acquire_lock (id) call my_lock_routine(my_lock) tha_notify_lock_acquired (id) ... call my_unlock_routine(my_lock) tha_notify_lock_released (id)
示例 2:
以下 C/C++ 示例显示了如何分别使用 tha_notify_sync_wait_begin() 和 tha_notify_sync_wait_end() 通知线程分析器用户定义的等待同步的开始和结束。
此外,该示例还显示了如何分别在后期同步之前和之后立即使用 tha_notify_sync_post_begin() 和 tha_notify_sync_post_end()。
#include "tha_interface.h" int busy_wait = 1; /* Code executed by thread 1 */ tha_notify_sync_wait_begin(&busy_wait); while (busy_wait) { no_op(); } tha_notify_sync_wait_end(&busy_wait); /* Code executed by thread 2 */ tha_notify_sync_post_begin(&busy_wait); busy_wait = 0; tha_notify_sync_post_end(&busy_wait);
示例 3:
以下 C/C++ 示例显示了如何使用 tha_check_datarace_mem() 避免报告开始数据争用。
volatile int is_bad = 0; /* * Each thread checks its assigned portion of data_array, * and sets the global flag is_bad to 1 once it finds a * bad data element. */ void check_bad_array (volatile data_t *data_array, unsigned int thread_id) { /* Do not check is_bad. */ tha_check_datarace_mem(&is_bad, sizeof(int), THA_CHK_OFF); int i; for (i=my_start(thread_id); i<my_end(thread_id); i++) { if (is_bad) break; else { if (is_bad_element(data_array[i])) { is_bad = 1; break; } } } tha_check_datarace_mem(&is_bad, sizeof(int), THA_CHK_ON); }
示例 4:
以下 C/C++ 示例显示了如何使用 tha_check_datarace_thr() 降低数据争用检测的开销-假设程序员只希望检查两个特定线程之间的数据争用。
/* * The following code is executed by the master thread. * Before creating any slave threads, the master thread * turns data race detection off for all threads. */ tha_check_datarace_thr(THA_CHK_THR_ALL, THA_CHK_OFF); pthread_create(...); /* * The following code is executed by the slave threads. * After a slave thread is created, it checks whether * it should turn data race detection on for itself. */ pthread_t tid = pthread_self(); if(tid == TID_TO_CHECK_1 || tid == TID_TO_CHECK_2) tha_check_datarace_thr(THA_CHK_THR_SELF, THA_CHK_ON);
如用法概要中所示,要使用 cc() 与 libtha 链接,建议的方法是在命令行上指定
-Rinstall-path/lib -Linstall-path/lib -ltha
其中 install-path 是指安装编译器的位置。
_________________________________________________________ | ATTRIBUTE TYPE | ATTRIBUTE VALUE | |__________________|______________________________________| | Stability Level | Evolving | |__________________|______________________________________|
analyzer (1) 、 collect (1) 、 collector (1) 、 er_print (1) 、 tha (1) 、 attributes (5)
线程分析器用户指南
性能分析器手册