volatile修飾子の理解と使用


1.volatile修飾子とは?
volatileキーワードは、オペレーティングシステム、ハードウェア、または他のスレッドなど、いくつかのコンパイラによって不明な要素によって変更できることを宣言するタイプ修飾子です.このキーワード宣言の変数に遭遇すると、コンパイラは変数にアクセスするコードを最適化せず、特殊なアドレスへの安定したアクセスを提供することができます.
2.簡単な例
volatileはコンパイラコンパイルの結果に影響します.volatile変数は随時変化する可能性があり,volatile変数に関する演算はコンパイル最適化を行わない.次のようになります.
volatile int i=10;
int j = i;
…
…
int k = i;

最適化されていない方法:コンパイラが生成した実行可能コードは、iのアドレスからデータをkに再読み込み最適化する方法:コンパイラは、iからデータを読み出すコード間のコードがiを操作していないことを2回発見したため、前回読んだデータをkに自動的に置く.
すなわち、volatileは、コンパイラiがいつでも変化する可能性があることを示し、それを使用するたびにiのアドレスから読み出さなければならないため、コンパイラが生成した実行可能コードは、iのアドレスからデータを読み直してkに置く.最適化の方法は、コンパイラがiからデータを読み出すコード間のコードがiを操作していないことを2回発見したため、前回読んだデータをkに自動的に配置することである.iから読み直すのではなく.これにより、iがレジスタ変数であるか、ポートデータを表すとエラーが発生しやすいため、volatileは特殊なアドレスへの安定したアクセスを保証し、エラーが発生しない.
次に、(VC 6)を使用する例を示します.
#include 

int main()
{
	int i = 10;
	int b;
	int a = i;
	printf("i = %d
", a); // i __asm { mov dword ptr [ebp-4], 20h } b = i; printf("i = %d
", b); return 0; }

コンパイル時にdebugとreleaseモードを選択すると、異なる結果が得られます.ここでdebugは最適化を行わないことを意味し,releaseはコンパイラが最適化する.真実がある:
3.レジスタの件
レジスタは、CPU内部にデータを格納するための小型の記憶領域であり、演算に関与するデータと演算結果を一時的に格納するために用いられる.アクセス速度:レジスタ>>cache>>RAMは現在のコンピュータ技術において、メインメモリのアクセス速度はCPUの操作よりずっと遅い.レジスタはCPUの高速処理の性能を十分に発揮し,中央プロセッサとメインメモリとの速度不整合の矛盾を緩和することができる.レジスタ内の変数の状態は、メモリ内のこの変数の状態と直接等しくありません.
4.マルチスレッド共有変数
Thread A:                   ThreadB:int k;                   ...gTest = 1;                   ......                        ......                        gTest= 2;...                        ...k = gTest;          ...
今回のスレッドでは、1つの変数を読み出すと、アクセス速度を向上させるためにコンパイラが最適化すると、まず1つのレジスタに変数を読み出すことがあります.以降、変数値を取得すると、レジスタから直接値を取得します.変数値がこのスレッドで変更されると、変数の新しい値copyがレジスタに同時に入力され、一致します.変数が他のスレッドなどによって値を変更した場合、レジスタの値はそれに応じて変更されず、アプリケーションが読み出す値と実際の変数値が一致しない.
5.ISR修正変数
static int i = 0;
int main()
{	…
	while(1)
	{ if(i) dosomething(); }
}
/* Interrupt service routine. */
void ISR(void)
{ i = 1; }

アクセスレジスタの速度はRAMより速いため、コンパイラは外部RAMへのアクセスを減らす最適化を行うのが一般的である.例えば、プログラムの本意はISR割り込み発生時にmainでdosomething関数を呼び出すことであるが、コンパイラはmain関数にiが修正されていないと判断するため、iからあるレジスタへの読み取り操作を1回だけ実行し、if判断のたびにこのレジスタの中の「iコピー」のみを使用し、dosomethingは永遠に呼び出されない可能性がある.変数にvolatile修飾を加えると、コンパイラはこの変数の読み書き操作が最適化されないことを保証します(必ず実行します).この例ではiもこのように説明すべきである.
6.volatileはいつ使用しますか?
volatile:“易失変数”?コンパイル時に最適化を行わず、「元のメモリアドレスに直接アクセス」
一般的にvolatileは、1、割り込みサービスプログラムで修正された他のプログラムが検出する変数にvolatileを加える必要がある.2、マルチタスク環境の下で各タスク間で共有するフラグはvolatileを加えるべきである.3、メモリマッピングのハードウェアレジスタ(ステータスレジスタなど)は、通常、volatileの説明を加えなければならない.なぜなら、読み書きのたびに異なる意味を持つ可能性があるからである.