🐸
なんでもatomicにするな
0. はじめに
マルチスレッドプログラムで、作業メモリをなんでもatomic変数にする人がいる。
良く言えば用心深い人。
ただ、マルチスレッド化の(大抵の)目的は高速化なのに、過剰な排他制御で本末転倒になる場合がある。
この記事では、排他制御が不要な場合と、必要な場合を作業メモリの観点で示す。
説明を単純化するため、スレッドが2つの場合を示す。
更新
- 2022.11.10: 排他制御が不要な場合1.3を、排他制御が必要に修正
1. 排他制御が不要な場合
1.1 作業メモリが違う
1.2 作業メモリが同じだが、読込だけ
1.3 作業メモリが同じだが、書込みするのは1スレッドだけ
2. 排他制御が必要な場合
2.1 作業メモリが同じで、2スレッド以上から書込む
2.2 作業メモリが同じで、2スレッド以上から読み書込き
2.3 作業メモリが同じだが、書込みするのは1スレッドだけ
3. まとめ
同じ作業メモリに書込みをするスレッドが2スレッド以上あれば排他制御が必要と覚える- 同じ作業メモリを読み書込みをするスレッドが2スレッド以上あれば排他制御が必要と覚える
- 例外はあるかもしれん(用心深い人は私です)
Discussion
図がわかりやすくて良いですね。
ただ1.3は書き込み操作が含まれるため排他制御が必要ではないでしょうか?
データ競合という問題で、C言語の例としては以下のページに記載があります。多くの言語で同じ問題が起きると思います。
コメントありがとうございます。
提示いただいたリンク先には2つの例があり、この記事で触れてない1.1の例外という意味で面白い題材です。
ちょっと深堀してみます。
リンク先の例①
2つのスレッドから異なる作業メモリを変更する(書込みする)ので、1.1の例外に該当しますね。
リンク先の解説にあるように
なので、C99では排他制御が必要です。図で書くと以下になると思います。
リンク先の例②
こちらも1.1の例外ですね。
リンク先の解説にあるように
なので、排他制御が必要です。図は例①とほぼ同じすね。
違いは以下なので、図は省略します
まとめ
この2例をまとめると、”異なる作業メモリに2スレッド以上で書込む場合、作業メモリが2バイト以下に隣接してると、競合する場合がある”
ということでしょう。
面白い話題のご提供ありがとうございました。
1.3については可視性の保証がないからダメだと思います。
(可視性を気にする必要のないアプリケーションなら問題ないですが、少数派でしょう)
以下の解説をどうぞ:
参考記事つきで、コメントありがとうございます。
ご指摘の通りです。
C++ではatomic変数にしないと、
異なるスレッドからの値が読めるようになるという意味の可視性を保証する術がなさそうなので
同期は必要ですね。
修正しておきます。