Oracle® Solaris Studio 12.4:线程分析器用户指南

退出打印视图

更新时间: 2014 年 12 月
 
 

用户定义的同步

线程分析器可以识别由 OpenMP、POSIX 线程和 Oracle Solaris 线程提供的大多数标准同步 API 和构造。但是,该工具无法识别用户定义的同步,如果代码中包含这样的同步,可能会误报数据争用。


注 -  为了避免报告此类误报的数据争用,线程分析器提供了一组 API,可用于在执行用户定义的同步时通知该工具。有关更多信息,请参见线程分析器用户 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 的读取由同一互斥锁加以保护,因此这两次访问之间不存在数据争用,并且该工具可以正确识别该情况。

第 100 行 data 的写入和第 205 行 data 的读取不受互斥锁的保护。但是,在程序逻辑中,第 205 行的读取总是发生在第 100 行的写入之后,原因是存在标志变量 ready_flag。因此,这两次数据访问之间不存在数据争用。但是,如果在运行时未实际对 pthread_cond_wait() 进行调用(第 202 行),该工具将报告这两次访问之间存在数据争用。如果在执行第 201 行之前执行了第 102 行,则在执行第 201 行时,循环条目测试就会失败,因此将跳过第 202 行。该工具会监视 pthread_cond_signal() 调用和 pthread_cond_wait() 调用,并可使它们成对以形成同步。如果未调用第 202 行的 pthread_cond_wait(),该工具并不知道第 100 行的写入总是在第 205 行的读取之前执行。因此,该工具认为它们是同时执行的,并报告它们之间的数据争用。

libtha(3C) 手册页和线程分析器用户 API说明了如何使用 API 避免报告此类误报的数据争用。