Sun Studio 12:线程分析器用户指南

2.5.1 用户定义的同步

线程分析器可以识别由 OpenMP、POSIX 线程和 Solaris 线程提供的大多数标准同步 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);
103   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 的值设置为一以指示已生成数据,然后调用 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 行上的读取之前执行的。因此,它认为它们是并发执行的,并报告它们之间的数据争用。

为了避免误报此类数据争用,线程分析器提供了一组 API,可以用来在执行用户定义的同步时通知该工具。有关更多信息,请参见A.1 线程分析器的用户 API