Cプログラマーは、変数が現在の実行スレッド外で変更される可能性があることを意味するために、しばしばvolatileと見なしています。その結果、共有データ構造が使用されている場合、カーネルコードでそれを使用したくなることがあります。つまり、揮発性型を一種の簡単なアトミック変数として扱うことが知られていますが、そうではありません。カーネルコードでvolatileを使用することはほとんど正しくありません。このドキュメントはその理由を説明しています。
volatileに関して理解するべき重要な点は、その目的が最適化を抑制することであり、それが本当にしたいことはほとんどないということです。カーネルでは、不要な同時アクセスから共有データ構造を保護する必要がありますが、これは非常に異なるタスクです。不要な同時実行から保護するプロセスにより、最適化関連のほとんどすべての問題がより効率的に回避されます。
揮発性と同様に、データへの同時アクセスを安全にするカーネルプリミティブ(スピンロック、ミューテックス、メモリバリアなど)は、不要な最適化を防ぐように設計されています。それらが適切に使用されている場合は、揮発性も使用する必要はありません。それでもvolatileが必要な場合は、ほぼ間違いなくどこかにコードのバグがあります。適切に作成されたカーネルコードでは、volatileは物事を遅くするためにのみ機能します。
カーネルコードの典型的なブロックを考えてみましょう:
spin_lock(&the_lock);
do_something_on(&shared_data);
do_something_else_with(&shared_data);
spin_unlock(&the_lock);
すべてのコードがロック規則に従っている場合、the_lockが保持されている間、shared_dataの値が予期せず変更されることはありません。そのデータを使用して再生する可能性のある他のコードは、ロックを待機しています。スピンロックプリミティブはメモリバリアとして機能します-それらは明示的にそのように書かれています-つまり、データアクセスはそれらの間で最適化されません。そのため、コンパイラはshared_dataの内容を知っていると考えるかもしれませんが、spin_lock()呼び出しはメモリバリアとして機能するため、知っていることをすべて忘れさせます。そのデータへのアクセスに最適化の問題はありません。
shared_dataがvolatileと宣言された場合でも、ロックは必要です。しかし、他の誰もそれを操作できないことがわかっている場合、コンパイラーはクリティカルセクション内のshared_dataへのアクセスを最適化することもできなくなります。ロックが保持されている間、shared_dataは揮発性ではありません。共有データを処理する場合、適切なロックは揮発性を不要にし、潜在的に有害にします。
揮発性ストレージクラスは、もともとメモリマップI / Oレジスタ用でした。カーネル内では、レジスタアクセスもロックで保護する必要がありますが、コンパイラがクリティカルセクション内でレジスタアクセスを「最適化」することも望まないでしょう。ただし、カーネル内では、I / Oメモリアクセスは常にアクセサ関数を介して行われます。ポインタを介してI / Oメモリに直接アクセスすることは好ましくなく、すべてのアーキテクチャで機能するわけではありません。これらのアクセサーは、不要な最適化を防ぐために記述されているため、揮発性は不要です。
揮発性を使用したくなる別の状況は、プロセッサが変数の値をビジー待機している場合です。ビジー待機を実行する正しい方法は次のとおりです。
while (my_variable != what_i_want)
cpu_relax();
cpu_relax()呼び出しは、CPU消費電力を下げるか、ハイパースレッドツインプロセッサに譲ることができます。また、メモリバリアとしても機能するため、揮発性は不要です。もちろん、多忙な待機は、一般的にそもそも反社会的行為です。
カーネルでvolatileが理にかなっているまれな状況がまだいくつかあります。
上記のアクセサ関数は、直接I / Oメモリアクセスが機能するアーキテクチャでは揮発性を使用する場合があります。基本的に、各アクセサー呼び出しは、それ自体が少し重要なセクションになり、プログラマーが期待どおりにアクセスできるようにします。
メモリを変更するインラインアセンブリコードですが、目に見える副作用はありません。GCCによって削除されるリスクがあります。asmステートメントにvolatileキーワードを追加すると、この削除を防ぐことができます。
jiffies変数は、参照されるたびに異なる値を持つことができるという点で特別ですが、特別なロックなしで読み取ることができます。したがって、jiffiesは不安定になる可能性がありますが、このタイプの他の変数の追加は強く推奨されません。この点で、Jiffiesは「愚かな遺産」の問題(Linusの言葉)と見なされます。それを修正することは、それが価値があるよりももっと面倒です。
I / Oデバイスによって変更される可能性のあるコヒーレントメモリ内のデータ構造へのポインタは、場合によっては、合法的に揮発性である可能性があります。ネットワークアダプターが使用するリングバッファーは、そのアダプターがポインターを変更して、どの記述子が処理されたかを示しますが、このような状況の例です。
ほとんどのコードでは、上記のvolatileの正当化は適用されません。その結果、volatileの使用はバグと見なされる可能性が高く、コードがさらに精査されることになります。volatileを使いたくなった開発者は、一歩下がって、本当に達成しようとしていることについて考えるべきです。