マルチスレッドプログラミングとvolatile

マルチスレッドを使った最適化のWEB記事を続けて見かけたのだが、みんなvolaileについてはスルーしているので補足してみる。volatileは変数単位でコンパイラの最適化機能を無効にする修飾詞です。C++にもC#にもJavaにも、主要な言語には大抵用意されています。volatile宣言を忘れると、Releaseビルドでしか発生しない、再現性の低い、達の悪いバグに襲われる事になります。
何故volatile宣言が必要なのかと言うと、最近のコンパイラは高度に最適化作業をおこないます。その結果として、プログラマが記述したとおりの順序で処理を実行しない事もあります。マルチスレッドで特に問題になるのが、命令の順番の入れ替えや、演算処理のループ外への移動です。
例えばループの中でA*B*2という計算をしていたとします。コンパイラは局所的に見て、ループ内で変数Bが変更される可能性が無い事を判断した場合、B*2演算をループの外に移動したりします。すると別スレッドで変数Bの値を変更しても、他スレッドのループ内の演算には反映されないという事になってしまいます。

コンパイラが最適化する前:
int a, b, d;
void funcA(void)
{
while (true)
{
a = funcB();
d = a * b * 2;
}
}

コンパイラが最適化した後:
int a, b, d;
void funcA(void)
{
int e = b * 2;
while (true)
{
a = funcB();
d = a * e;
}
}

実はVisual C++やC#ではstatic変数やグローバル変数を無条件にvolatileな変数として扱うようになっています。スレッド間で共有するような変数の多くはstatic変数やグローバル変数ですから、殆どの場合volatile宣言を忘れていても動いてしまいます。でもそのために、ケアが必要だと言う事も忘れがちなのです。

コメントを残す

メールアドレスが公開されることはありません。