不可分操作(アトミック操作)とは
情報工学における不可分操作(アトミック操作)とは、複数の操作を組み合わせて一つの処理単位とし、システム全体から見てその処理が分割不可能に見えるようにする技術です。これは、システムが複数の
プロセスやスレッドによって並行して動作する際に、データの不整合を防ぐために非常に重要です。
不可分操作の条件
不可分操作は、以下の2つの主要な条件を満たす必要があります。
1.
不可視性: 操作の実行中、その中間の状態は他の
プロセスから観測できないこと。つまり、操作が完了するまでは、他の
プロセスはその操作が開始されたことすら認識できないようにする必要があります。
2.
オールオアナッシング: 操作が一部でも失敗した場合、操作全体が失敗として扱われ、システムの状態は操作開始前の状態にロールバックされること。これにより、操作が途中で中断された場合にデータの不整合を防ぎます。
これらの条件により、不可分操作はシステムから見て「完全に成功した」か「完全に失敗した」のどちらかの状態しか認識されません。この性質から、原子操作とも呼ばれます。
不可分操作の重要性
不可分操作は、マルチプロセッサ環境だけでなく、シングルプロセッサ環境においても重要です。なぜなら、プロセッサの処理が一時中断されたり、他の
プロセスに切り替わったりする可能性があるためです。もし不可分性が保証されない場合、システムは不正な状態になり、予期せぬエラーを引き起こす可能性があります。
単純な例
例えば、メモリ上のカウンタ値をインクリメントする操作を考えてみましょう。通常、この操作は以下の3つのステップで行われます。
1. カウンタの値をメモリから読み出す。
2. 読み出した値に1を加算する。
3. 加算した値をメモリに書き戻す。
もしこの操作が不可分でなければ、複数の
プロセスが同時に同じカウンタをインクリメントしようとした場合、以下の様な問題が発生する可能性があります。
1.
プロセスAがカウンタ値を読み出す。
2.
プロセスAが値に1を加算する。
3.
プロセスAが結果を書き戻す前に、
プロセスBが実行を開始する。
4.
プロセスBがカウンタ値を読み出す(この時、値は
プロセスAが読み出した値と同じ)。
5.
プロセスBが値に1を加算する。
6.
プロセスBが結果を書き戻す。
7.
プロセスAが実行を再開し、結果を書き戻す(
プロセスBの処理が上書きされる)。
この結果、カウンタは2回インクリメントされるはずが、1回しかインクリメントされないという問題が発生します。この現象は「競合状態」と呼ばれ、不可分操作によって避けることができます。
実世界の複雑な例
現実のシステムでは、操作はもっと複雑になり、例えば64ビットの値をメモリから読み出す操作は、32ビットのリードを2回行うことで実装されている場合があります。この場合、最初の32ビットを読み込んだ後、次の32ビットを読み込む前に他の
プロセスが値を変更してしまう可能性があります。結果として、読み込まれた64ビットの値は、変更前とも変更後とも異なる、無意味な値になる可能性があります。
さらに、このような問題は
プロセスの実行順序に依存するため、デバッグが非常に困難になります。
CPUアーキテクチャと不可分操作
CPUアーキテクチャによって、不可分操作の実装方法は異なります。
RISCアーキテクチャでは、読み込みと書き込みが別々の命令で行われるため、単純なインクリメント操作でも不可分性を保証するための特別な措置が必要です。一方、x86アーキテクチャのようなCISCアーキテクチャでは、インクリメントやデクリメントを1つの命令で実行できるため、不可分性を容易に実現できます。
しかし、究極的には、不可分操作は、メモリアドレスへの読み込みと書き込みを不可分に行う操作に帰着します。これは、テスト・アンド・セット操作や、コンペア・アンド・スワップ操作によって実現されます。
RISCアーキテクチャでは、これらの操作を効率的に実現するために、Load-Link/Store-Conditionalといった特別な命令が導入されています。
ロックと不可分操作
クリティカルセクションを保護するためにロックを使用することが一般的ですが、ロック自体もハードウェアのサポートなしには、単なるメモリ上のデータにすぎません。ソフトウェアだけでロックを実装することは可能ですが、効率が悪いため、上述のような不可分操作を利用して、効率的なロック機構を実装します。
関連項目
不可分操作に関連する重要な概念を以下に示します。
テスト・アンド・セット
コンペア・アンド・スワップ
フェッチ・アンド・アッド
Load-Link/Store-Conditional
クリティカルセクション
セキュリティホール
一貫性モデル
線形化可能性
* ACID
これらの概念を理解することで、並行処理における様々な問題を解決し、堅牢なシステムを構築するための知識を深めることができます。