Oracle® Developer Studio 12.5: スレッドアナライザユーザーズガイド

印刷ビューの終了

更新: 2016 年 6 月
 
 

データの競合チュートリアルのソースファイル

このチュートリアルでは、データの競合を含んだ 2 つのプログラムを使用します。

  • 最初のプログラムは素数を見つけます。このプログラムは C 言語で作成され、OpenMP 指令で並列化されています。ソースファイルは prime_omp.c と呼ばれます。

  • 2 番目のプログラムも素数を見つけるもので、やはり C 言語で作成されます。ただし、これは OpenMP 指令でなく POSIX スレッドで並列化されます。ソースファイルは prime_pthr.c と呼ばれます。

データの競合チュートリアルのソースファイルの入手

このチュートリアルで使用するソースファイルは、Oracle Developer Studio 開発者ポータルのダウンロードエリアからダウンロードできます。

サンプルファイルをダウンロードして展開したあと、OracleDeveloperStudio12.5-Samples/ThreadAnalyzer ディレクトリからサンプルを見つけることができます。サンプルは、prime_omp および prime_pthr サブディレクトリにあります。各サンプルディレクトリには、手順に関する DEMO ファイルと Makefile ファイルが 1 つずつ含まれていますが、このチュートリアルではそれらの手順に従わず、Makefile も使用しません。代わりに、コマンドを個別に実行していきます。

このチュートリアルに従うには、サンプルディレクトリから prime_omp.c prime_pthr.c ファイルを別のディレクトリにコピーするか、独自のファイルを作成し、次のコードリストからコードをコピーします。

prime_omp.c のソースコード

このセクションでは、prime_omp.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 <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	}

prime_pthr.c のソースコード

このセクションでは、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	
    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	}

prime_omp.c および prime_pthr.c でのデータの競合の影響

コードに競合状態が存在する場合は、メモリーアクセスの順序が定まらないため、実行するたびにその時の順序によって計算結果が異なります。prime_omp および prime_pthr プログラムの正しい答えは 1229 です。

例をコンパイルして実行できるので、prime_omp または prime_pthr を実行すると、コード内のデータの競合によって誤ったまたは矛盾した結果が生じることがわかります。

次の例では、プロンプトにコマンドを入力して、prime_omp プログラムをコンパイルし実行します。

% 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

次の例では、プロンプトにコマンドを入力して、prime_pthr プログラムをコンパイルし実行します。

% 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

各プログラムを 3 回実行した結果が矛盾していることに注意してください。矛盾した結果が表示されるまで、4 回以上プログラムを実行する必要がある場合もあります。

次に、データの競合が生じている位置を特定できるように、コードを計測し、実験を作成します。