Oracle® Developer Studio 12.5:线程分析器用户指南

退出打印视图

更新时间: 2016 年 6 月
 
 

诊断数据争用的原因

本节介绍诊断数据争用原因的基本策略。

检查数据争用是否为误报

误报数据争用是指线程分析器已报告但实际并未发生的数据争用。换言之,这是“假警报”。线程分析器会尽可能减少误报数量,但在某些情况下,该工具无法完成精确的工作并可能误报数据争用。

由于误报的数据争用不是真正的数据争用,并不会影响程序的行为,因此可将其忽略。

有关误报数据争用的一些示例,请参见误报。有关如何从报告中消除误报数据争用的信息,请参见线程分析器用户 API

检查数据争用是否为良性

良性数据争用是指特意允许的数据争用,其存在不会影响程序正确性。

一些多线程应用程序会特意使用可能导致数据争用的代码。由于这些数据争用是专门设计的,所以不需要进行修复。但在某些情况下,要使这样的代码正确运行会相当棘手。应仔细检查这些数据争用。

有关良性争用的更多详细信息,请参见误报

修复错误而不是修复数据争用

线程分析器可以帮助查找程序中的数据争用,但是它无法自动查找程序中的错误,也不会建议如何修复找到的数据争用。数据争用可能是由某个错误引入的。这种情况下,必须找到并修复该错误。仅仅消除数据争用并不是正确的做法,这样做可能会使进一步的调试更加困难。

修复 prime_omp.c 中的错误

本节介绍如何修复 prime_omp.c 中的错误。有关所列的完整文件内容,请参见prime_omp.c 的源代码

将第 49 行和第 50 行移动到 critical(临界)段中,以便消除数组 primes[ ] 的元素上的数据争用。

46      #pragma omp parallel for
47      for (i = 2; i < N; i++) {
48        if ( is_prime(i) ) {
             #pragma omp critical              
            {    
49             primes[total] = i;
50             total++;
                }
51           }
52      }

也可以按照如下所示将第 49 行和第 50 行移动到两个 critical(临界)段中,但此更改方式无法更正程序:

46      #pragma omp parallel fo
47      for (i = 2; i < N; i++) {
48          if ( is_prime (i) ) {
                 #pragma omp critical
                 {
49                  primes [total] = i;
                 }
                 #pragma omp critical
                 {
50                  total++;
                 }
51          }
52     }

包含第 49 行和第 50 行的临界段将会消除数据争用,因为线程会使用互斥锁控制它们对 primes[ ] 数组的访问。但是,程序仍是错误的。两个线程可能会使用同一 total 值更新 primes[ ] 的同一元素,而 primes[ ] 的某些元素可能根本不会被赋值。

第二个数据争用(第 22 行中从 pflag[ ] 的读取与第 25 行中对 pflag[ ] 的写入之间的数据争用)实际上是良性争用,因为它并不会导致错误结果。没有必要修复良性数据争用。

修复 prime_pthr.c 中的错误

本节介绍如何修复 prime_pthr.c 中的错误。有关所列的完整文件内容,请参见prime_pthr.c 的源代码

要删除第 50 行中对 prime[ ] 的数据争用以及第 44 行中对 total 的数据争用,请围绕这两行添加互斥锁/解锁,以便每次只有一个线程可以更新 prime[ ] 和 total。

第 59 行中对 i 的写入与第 39 行中同一内存位置(名为 *arg)的读取之间的数据争用表明不同的线程对变量 i 进行的共享访问存在问题。prime_pthr.c 中的初始线程在第 59-61 行通过循环方式创建子线程,并调度它们执行函数 work()。循环索引 i 按地址传递到 work()。由于所有线程都访问 i 的同一内存位置,因此每个线程的 i 值不会保持唯一,而会随着初始线程对循环索引的递增而改变。由于不同的线程使用同一个 i 值,因此就会发生数据争用。修复该问题的一种方法是按值(而不是按地址)将 i 传递给 work()

以下代码是 prime_pthr.c 的更正版本:

     1	/* 
     2	 * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All Rights Reserved.
     3	 */
     4	
     5	#include <stdio.h>
     6	#include <math.h>
     7	#include <pthread.h>
     8	
     9	#define THREADS 4
    10	#define N 10000
    11	
    12	int primes[N];
    13	int pflag[N];
    14	int total = 0;
    15	pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    16	
    17	int is_prime(int v)
    18	{
    19	    int i;
    20	    int bound = floor(sqrt(v)) + 1;
    21	
    22	    for (i = 2; i < bound; i++) {
    23	        /* no need to check against known composites */ 
    24	        if (!pflag[i])
    25	            continue;
    26	        if (v % i == 0) {
    27	            pflag[v] = 0;
    28	            return 0;
    29	        }
    30	    }
    31	    return (v > 1); 
    32	}
    33	
    34	void * work(void *arg)
    35	{
    36	    int start;
    37	    int end;
    38	    int i;
    39	    
    40	    start = (N/THREADS) * ((int)arg) ;
    41	    end = start + N/THREADS;
    42	    for (i = start; i < end; i++) {
    43	        if ( is_prime(i) ) {
    44	            pthread_mutex_lock(&mutex);
    45	            primes[total] = i;
    46	            total++;        
    47	            pthread_mutex_unlock(&mutex);
    48	        }
    49	    }
    50	    return NULL;
    51	}
    52	
    53	int main(int argn, char **argv)
    54	{
    55	    int i;
    56	    pthread_t tids[THREADS-1];
    57	
    58	    for (i = 0; i < N; i++) {
    59	        pflag[i] = 1; 
    60	    }
    61	
    62	    for (i = 0; i < THREADS-1; i++) {
    63	        pthread_create(&tids[i], NULL, work, (void *)i);
    64	    }
    65	
    66	    i = THREADS-1;
    67	    work((void *)i);
    68	    
    69	    for (i = 0; i < THREADS-1; i++) {
    70	        pthread_join(tids[i], NULL);
    71	    }
    72	
    73	    printf("Number of prime numbers between 2 and %d: %d\n",
    74	           N, total);
    75	
    76	    return 0;
    77	}