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

2.6.1 用于查找素数的程序

文件 omp_prime.c 中的线程通过执行函数 is_prime() 来检查一个整数是否为素数。

11 int is_prime(int v)
    12 {
    13     int i;
    14     int bound = floor(sqrt ((double)v)) + 1;
    15      
    16     for (i = 2; i < bound; i++) {
    17         /* No need to check against known composites */ 
    18         if (!pflag[i]) 
    19             continue;
    20         if (v % i == 0) { 
    21             pflag[v] = 0;
    22             return 0;
    23         }
    24     }
    25     return (v > 1); 
    26 }

线程分析器报告在第 21 行上 pflag[] 的写入和第 18 行上 pflag[] 的读取之间存在数据争用。但是,此数据争用是良性的,因为它不会影响最终结果的正确性。在第 18 行上,线程检查对于 i 的给定值 pflag[i] 是否等于零。如果 pflag[i] 不等于零,则表明 i 是已知的合数(换句话说,知道 i 不是素数)。因此,无需检查 v 是否可被 i 整除;我们只需检查 v 是否可被某个素数整除。因此,如果 pflag[i] 等于零,则线程将继续执行 i 的下一个值。如果 pflag[i] 不等于零且 v 可被 i 整除,则线程将为 pflag[v] 分配零,以指示 v 不是素数。

从正确性方面看,多个线程检查同一 pflag[] 元素并同时向其写入是可以的。pflag[] 元素的初始值为一。当线程更新该元素时,它们为该元素分配零值。即,线程在该元素的同一内存字节的同一位中存储零。在当前的体系结构中,可以假定那些存储是原子的。这意味着,线程读取该元素时,读取的值要么为一,要么为零。如果线程在为其分配零值之前检查给定 pflag[] 元素(第 18 行),则它执行第 20-23 行。如果在此期间,另一线程为该同一 pflag[] 元素(第 21 行)分配零值,则最终结果不变。在本质上,这意味着第一个线程不必要地执行了第 20-23 行。