アトミック アクセスを確保するには、割り込みを無効にする必要があります。読み取り中に他のプロセスがその変数にアクセスして、潜在的に変更することは望ましくありません。
組み込みコンピューティングの紹介から:
アトミック アクセスの必要性
このシナリオを想像してみてください: 8 ビットの uC で実行されているフォアグラウンド プログラムは、16 ビットの変数を調べる必要があり、それを X と呼びます。重要ではありません)、16 ビット値を調べます。ここで、その 16 ビット変数を変更する関連付けられた ISR による割り込みを想像してください。さらに、変数の値が、プログラム実行中のある時点で 0x1234 になったとします。起こりうる非常に悪いことは次のとおりです。
- フォアグラウンドは上位バイト (0x12) をロードします
- ISR が発生し、X を 0xABCD に変更します
- フォアグラウンドは下位バイト (0xCD) をロードします
- フォアグラウンド プログラムは、0x12CD の 16 ビット値を認識します。
問題は、変数 X にアクセスするための CPU 命令が割り切れる可能性があるため、分割できないと思われるデータの一部である変数 X が、実際にはアクセスの過程で変更されたことです。したがって、変数 X のロードは破損しています。変数の読み取り順序は関係ないことがわかります。この例で順序を逆にすると、変数は 0x12CD ではなく 0xAB34 として誤って読み取られます。いずれにせよ、読み取られた値は古い有効値 (0x1234) でも新しい有効値 (0xABCD) でもありません。
ISR 参照データを書き込むのは良くありません。今回は、フォアグラウンド プログラムが ISR のために以前の値 0x1234 を書き込んだ後、新しい値 0xABCD を書き込む必要があると仮定します。この場合、VBT は次のようになります。
- フォアグラウンドは新しい上位バイト (0xAB) を格納します
- ISR が発生し、X を 0xAB34 として読み取る
- フォアグラウンドは新しい下位バイト (0xCD) を格納します
コード (今回は ISR) は、以前の有効な値 0x1234 も新しい有効な値 0xABCD も認識せず、無効な値 0xAB34 を認識します。
C では 1 つの命令のように見えるかもしれませspiTxRxByteCount &= ~0x0100;
んが、実際には CPU にとっては複数の命令です。GCC でコンパイルすると、アセンブリ リストは次のようになります。
57:atomic.c **** spiTxRxByteCount &= ~0x0100;
68 .loc 1 57 0
69 004d A1000000 movl _spiTxRxByteCount, %eax
69 00
70 0052 80E4FE andb $254, %ah
71 0055 A3000000 movl %eax, _spiTxRxByteCount
71 00
これらの命令のいずれかの間に割り込みが発生し、データが変更された場合、最初の ISR が誤った値を読み取る可能性があります。そのため、割り込みを操作する前に割り込みを無効にし、変数を宣言する必要がありますvolatile
。