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

Exit Print View

Updated: June 2016
 
 

Data Race Tutorial Source Files

This tutorial relies on two programs, both of which contain data races:

  • The first program finds prime numbers. It is written with C and is parallelized with OpenMP directives. The source file is called prime_omp.c.

  • The second program also finds prime numbers and is also written with C. However, it is parallelized with POSIX threads instead of OpenMP directives. The source file is called prime_pthr.c.

Getting the Data Race Tutorial Source Files

You can download the source files used in this tutorial from the Download area (http://www.oracle.com/technetwork/server-storage/solarisstudio/downloads/index.html) of the Oracle Developer Studio developer portal.

After you download and unpack the sample files, you can find the samples in the OracleDeveloperStudio12.5-Samples/ThreadAnalyzer directory. The samples are located in the prime_omp and prime_pthr subdirectories. Each sample directory includes a Makefile and a DEMO file of instructions, but this tutorial does not follow those instructions or use the Makefile. Instead, you are instructed to execute commands individually.

To follow the tutorial, you can copy the prime_omp.c and prime_pthr.c files from the samples directories to a different directory, or you can create your own files and copy the code from the following code listings.

Source Code for prime_omp.c

This section shows the source code for prime_omp.c as follows:

     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 <omp.h>
     8	
     9	#define THREADS 4
    10	#define N 10000
    11	
    12	int primes[N];
    13	int pflag[N];
    14	
    15	int is_prime(int v)
    16	{
    17	    int i;
    18	    int bound = floor(sqrt(v)) + 1;
    19	    
    20	    for (i = 2; i < bound; i++) {
    21	        /* no need to check against known composites */ 
    22	        if (!pflag[i]) 
    23	            continue;
    24	        if (v % i == 0) { 
    25	            pflag[v] = 0;
    26	            return 0;
    27	        }
    28	    }
    29	    return (v > 1); 
    30	}
    31	
    32	int main(int argn, char **argv)
    33	{
    34	    int i;
    35	    int total = 0;
    36	
    37	#ifdef _OPENMP
    38	    omp_set_dynamic(0);
    39	    omp_set_num_threads(THREADS);
    40	#endif
    41	
    42	    for (i = 0; i < N; i++) {
    43	        pflag[i] = 1; 
    44	    }
    45	    
    46	    #pragma omp parallel for
    47	    for (i = 2; i < N; i++) {
    48	        if ( is_prime(i) ) {
    49	            primes[total] = i;
    50	            total++;
    51	        }
    52	    }
    53	
    54	    printf("Number of prime numbers between 2 and %d: %d\n",
    55	           N, total);
    56	
    57	    return 0;
    58	}

Source Code for prime_pthr.c

This section shows source code for prime_pthr.c as follows:

     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	
    16	int is_prime(int v)
    17	{
    18	    int i;
    19	    int bound = floor(sqrt(v)) + 1;
    20	
    21	    for (i = 2; i < bound; i++) {
    22	        /* no need to check against known composites */ 
    23	        if (!pflag[i])
    24	            continue;
    25	        if (v % i == 0) {
    26	            pflag[v] = 0;
    27	            return 0;
    28	        }
    29	    }
    30	    return (v > 1); 
    31	}
    32	
    33	void * work(void *arg)
    34	{
    35	    int start;
    36	    int end;
    37	    int i;
    38	
    39	    start = (N/THREADS) * (*(int *)arg);
    40	    end = start + N/THREADS;
    41	    for (i = start; i < end; i++) {
    42	        if ( is_prime(i) ) {
    43	            primes[total] = i;
    44	            total++;        
    45	        }
    46	    }
    47	    return NULL;
    48	}
    49	
    50	int main(int argn, char **argv)
    51	{
    52	    int i;
    53	    pthread_t tids[THREADS-1];
    54	
    55	    for (i = 0; i < N; i++) {
    56	        pflag[i] = 1; 
    57	    }
    58	
    59	    for (i = 0; i < THREADS-1; i++) {
    60	        pthread_create(&tids[i], NULL, work, (void *)&i);
    61	    }
    62	
    63	    i = THREADS-1;
    64	    work((void *)&i);
    65	        
    66	    for (i = 0; i < THREADS-1; i++) {
    67	        pthread_join(tids[i], NULL);
    68	    }
    69	
    70	    printf("Number of prime numbers between 2 and %d: %d\n",
    71	           N, total);
    72	
    73	    return 0;
    74	}

Effect of Data Races in prime_omp.c and prime_pthr.c

When there is a race condition in the code, the order of memory accesses is non-deterministic so the computation gives different results from run to run. The correct answer in the prime_omp and prime_pthr programs is 1229.

You can compile and run the examples so you can see that the execution of prime_omp or prime_pthr produces incorrect and inconsistent results because of the data races in the code.

In the following example, type the commands at the prompt to compile and run the prime_omp program:

% cc -xopenmp=noopt -o prime_omp prime_omp.c -lm
%
% ./prime_omp
Number of prime numbers between 2 and 10000: 1229
% ./prime_omp
Number of prime numbers between 2 and 10000: 1228
% ./prime_omp
Number of prime numbers between 2 and 10000: 1180

In the following example, type the commands at the prompt to compile and run the prime_pthr program:

% cc -mt -o prime_pthr prime_pthr.c -lm
%
% ./prime_pthr
Number of prime numbers between 2 and 10000: 1140
% ./prime_pthr
Number of prime numbers between 2 and 10000: 1122
% ./prime_pthr
Number of prime numbers between 2 and 10000: 1141

Notice the inconsistency of the results of the three runs of each program. You might need to run the programs more than three times to see inconsistent results.

Next, you instrument the code and create experiments so you can find out where the data races are occurring.