Go to main content
Oracle® Developer Studio 12.6: Thread Analyzer User's Guide

Exit Print View

Updated: June 2017
 
 

Diagnosing the Cause of a Data Race

This section provides a basic strategy to diagnosing the cause of data races.

Check Whether or Not the Data Race is a False Positive

A false positive data race is a data race that is reported by Thread Analyzer, but has actually not occurred. In other words, it is a "false alarm". Thread Analyzer tries to reduce the number of false positives reported. However, there are cases where the tool is not able to do a precise job and might report false positive data races.

You can ignore a false positive data race because it is not a genuine data race and, therefore, does not affect the behavior of the program.

See False Positives for some examples of false positive data races. For information on how to remove false positive data races from the report, see Thread Analyzer User APIs.

Check Whether or Not the Data Race is Benign

A benign data race is an intentional data race whose existence does not affect the correctness of the program.

Some multithreaded applications intentionally use code that might cause data races. Since the data races are there by design, no fix is required. In some cases, however, it is quite tricky to get such codes to run correctly. These data races should be reviewed carefully.

See False Positives for more detailed information about benign races.

Fix the Bug, Not the Data Race

Thread Analyzer can help find data races in the program, but it cannot automatically find bugs in the program nor suggest ways to fix the data races found. A data race might have been introduced by a bug. It is important to find and fix the bug. Merely removing the data race is not the right approach, and could make further debugging even more difficult.

Fixing Bugs in prime_omp.c

This section describes how to fix the bug in prime_omp.c. See Source Code for prime_omp.c for a complete file listing.

Move lines 49 and 50 into a critical section in order to remove the data race on elements of the array 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       }

You could also move lines 49 and 50 into two critical sections as follows, but this change fails to correct the program:

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     }

The critical sections around lines 49 and 50 get rid of the data race because the threads are using mutual exclusive locks to control their accesses to the primes[ ] array. However, the program is still incorrect. Two threads might update the same element of primes[ ] using the same value of total, and some elements of primes[ ] might not be assigned a value at all.

The second data race, between a read from pflag[ ] from line 22 and a write to pflag[ ] from line 25, is actually a benign race because it does not lead to incorrect results. It is not essential to fix benign data races.

Fixing Bugs in prime_pthr.c

This section describes how to fix the bug in prime_pthr.c. See Source Code for prime_pthr.c for a complete file listing.

To remove the data race on prime[ ] at line 50, as well as the data race on total at line 44, add a mutex lock/unlock around these two lines so only one thread can update prime[ ] and total at a time.

The data race between the write to i on line 59 and the read of the same memory location (named *arg) on line 39 reveal a problem in the shared access to the variable i by different threads. The initial thread in prime_pthr.c creates the child threads in a loop in lines 59-61, and dispatches them to execute the function work(). The loop index i is passed to work() by address. Since all threads access the same memory location for i, the value of i for each thread will not remain unique, but will change as the initial thread increments the loop index. As different threads use the same value of i, data races occur. One way to fix the problem is to pass i to work() by value, instead of by address.

The following code is the corrected version of 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	}