複数スレッドが同じ静的変数にアクセスすると競合が起きます。
静的変数とはstatic変数とグローバル(externも同じ)変数を指します。
EMC組み込みマルチコアサミット2020、セミナー資料より
作成中のプログラムでは先頭の3行で宣言している変数がこれに該当します。
これらの変数へは、スレッドとして複数個動作するsub関数から直接、またはmul1関数等の子関数を通してアクセスします。もし他のスレッドと同時にアクセスし競合してしまったら、書いた値を使い終わる前に他のスレッドで上書きされ、異なる値を読み出してしまいます。
競合を防ぐためには、スレッド毎に変数を持つ方法と、排他制御する方法があります。排他制御処理は他のスレッドをガードする処理とガードを解除する処理を挿入するので、性能を求めるならスレッド毎に変数を持った方が良いのですが、処理の都合上、排他処理できないこともあります。
このプログラムの場合、赤色の宣言変数は関数内の一連の処理途中で一時的に使用する変数なので、ローカル変数にすることが可能です。
しかし、青色の宣言変数は、検出データを数えたり情報を保存するためのもので、関数が終わっても次の呼び出しで引き続き使用します。このためローカル変数にはできません。
競合を回避するために変更したプログラムは次の通りです。
EMC組み込みマルチコアサミット2020、セミナー資料より
static変数をローカル変数(オート変数)に変更したので、子関数も使えるよう引数として渡しました。
排他処理はOpenMP仕様の下記の1行を追加することで対策できますが、このブロックの前後には排他処理の設定と解除の命令(マシン語やシステムコール)が作られるので性能は落ちます。
#pragma omp critical(crit_val)
この改造により、プログラムは正常に動作するようになりました。
次回は、このプログラムの動作結果について説明します。
コメントをお書きください