「OpenMPでのアトミックな処理」の版間の差分

提供: C言語入門
移動: 案内検索
(ページの作成:「並列プログラミングでは、<u>処理を'''アトミック'''に行わないといけない場合があります</u>。クリティカルリージョン、クリ...」)
(相違点なし)

2016年1月20日 (水) 19:06時点における版

並列プログラミングでは、処理をアトミックに行わないといけない場合があります。クリティカルリージョン、クリティカルセクションと呼ばれるものです。大抵は、ロックをすることで実現されます。

読み方

atomic
あとみっく

概要

プログラムを並列化すると困るのが、共有される変数へのアクセスです。

スレッドが1つしか存在しない場合には、そのスレッドしか、リソースにアクセスしないので、問題は起きません。

しかし、スレッドが2つ以上になり、リソースをスレッド間で共有しはじめたときに、問題は発生します。

プログラムが以下の処理を行うときに、複数のスレッドが同じ処理を行うと、どうなるでしょうか?

  1. データの読み出し
  2. データの加工
  3. データの保存

2つのスレッドが以下のように動作すれば、問題はありません。

thread 1
データの読み出し
データの加工
データの保存
                  thread 2
                  データの読み出し
                  データの加工
                  データの保存

しかし、以下のように、スレッドが同時に動いている場合、データへのアクセスが競合状態(レースコンディション)に陥っています。

thread 1           thread 2
データの読み出し
                  データの読み出し
データの加工
                  データの加工
データの保存
                  データの保存

行業状態を避けるために、クリティカルリージョン(クリティカルセクション)をアトミックに処理するために、ロックを利用します。

OpenMP でのアトミックな処理

OpenMP では、 プラグマディレクティブ を用いて、プログラムをアトミックに処理することができます。

#pragma omp atomic

を記述するだけで処理はアトミックになります。

以下にシンプルな例を示します。

int i = 0;
{
#pragma omp atomic
	i++;
	printf ("i=%d\n", i);
}

atomic を用いたシンプルな例

ソースコード atomic2.c

/*
 * atomic1.c
 * Copyright (C) 2016 kaoru <kaoru@localhost>
 */
#include <stdio.h>
#include <stdlib.h>
 
int
main(int argc, char *argv[])
{
        int i = 0;
        {
#pragma omp atomic
                i++;
                printf ("i=%d\n", i);
        }
        exit(EXIT_SUCCESS);
}

コンパイル

$ gcc5 -std=c11 -Wl,-rpath=/usr/local/lib/gcc5/ \
-fopnemp atomic2.c -o atomic2

実行例

% ./atomic2
i=1

アセンブリ言語レベルでのコード

プラグマディレクティブを用いた場合と、そうではない場合を比較してみましょう。 gcc(gcc5)コンパイラを用いて、 -fopenmp なし、と -fopenmp あり の場合に出力されるアセンブリ言語のコードを確認しました。

以下は、atomic なし の場合です。

addl    $1, -4(%rbp)

以下は、atomic あり の場合です。

lock addl       $1, -4(%rbp)

アセンブリ言語のレベルでは、 lock が指定されていることがわかります。

並列化したプログラムのアトミックを用いた例

ソースコード atomic1.c

/*
 * atomic1.c
 * Copyright (C) 2016 kaoru <kaoru@localhost>
 */
 
#include <stdio.h>
#include <stdlib.h>
 
int
main(int argc, char *argv[])
{
        int i = 0;
#pragma omp parallel
        {
#pragma omp atomic
                i++;
                printf ("i=%d\n", i);
        }
        exit(EXIT_SUCCESS);
}

コンパイル

$ gcc5 -std=c11 -Wl,-rpath=/usr/local/lib/gcc5/ \
-fopnemp atomic1.c -o atomic1

実行例

% ./atomic1
i=1
i=2

クリティカルセクションとアトミックオペレーションの違い

OpenMPには、

  • atomic
  • critical

が存在します。

クリティカルセクション

  • ブロックのコードの直列化(serialization)を保証します。
  • name タグを利用して、ブロックのグループを直列化できます。
  • スピードが遅いです。

アトミックオペレーション

  • スピードが速いです。
  • 特別なオペレーションの直列化だけを保証します。

関連項目