39

キャッシュはプロセッサに対して透過的にキャッシュ ハードウェアによって制御されるため、C プログラムで揮発性変数を使用する場合、プログラムがキャッシュではなく指定された実際のメモリ アドレスから毎回データを読み取ることがどのように保証されるのでしょうか。

私の理解では、

  1. Volatile キーワードは、変数参照を最適化せず、コードでプログラムされたとおりに読み取る必要があることをコンパイラに伝えます。

  2. キャッシュはキャッシュ ハードウェアによって透過的に制御されるため、プロセッサがアドレスを発行するとき、データがキャッシュからのものかメモリからのものかはわかりません。

したがって、必要なたびにメモリアドレスを読み取る必要がある場合、キャッシュからではなく必要なアドレスから参照されるようにするにはどうすればよいですか?

どういうわけか、これら 2 つの概念はうまく適合しません。その方法を明確にしてください。

(キャッシュにライトバック ポリシーがあると仮定します (問題の分析に必要な場合))

ありがとう、マイクロカーネル:)

4

7 に答える 7

36

ファームウェア開発者はこちら。これは組み込みプログラミングの標準的な問題であり、多くの (非常に経験豊富な) 開発者をつまずかせる問題です。

ハードウェアレジスタにアクセスしようとしており、そのレジスタ値は時間の経過とともに変化する可能性があると思います (割り込みステータス、タイマー、GPIO 表示など)。

キーワードは解決策のvolatile一部にすぎず、多くの場合は必要ありません。これにより、変数が使用されるたびにメモリから再読み取りされます (コンパイラによって最適化されたり、複数の使用にわたってプロセッサレジスタに格納されたりするのではなく)。ただし、読み取られる「メモリ」が実際のハードウェアレジスタであるかどうか対キャッシュされた場所はコードには不明であり、volatileキーワードの影響を受けません。関数がレジスタを 1 回しか読み取らない場合は、おそらくオフvolatileのままにすることができますが、原則として、ほとんどのハードウェア レジスタを として定義することをお勧めしvolatileます。

より大きな問題は、キャッシングとキャッシュの一貫性です。ここでの最も簡単な方法は、レジスタがキャッシュされていないアドレス空間にあることを確認することです。つまり、レジスタにアクセスするたびに、メモリをキャッシュするのではなく、実際のハードウェア レジスタを読み書きすることが保証されます。より複雑ですが、パフォーマンスが向上する可能性があるアプローチは、キャ​​ッシュされたアドレス空間を使用し、このような特定の状況でコードを手動でキャッシュの更新を強制することです。どちらのアプローチでも、これがどのように達成されるかはアーキテクチャに依存し、問題の範囲を超えています。MTRR (x86 用)、MMU、ページ テーブルの変更などが含まれる可能性があります。

それが役立つことを願っています。何か見逃した場合はお知らせください。回答を拡大します。

于 2011-10-24T15:27:42.817 に答える
9

あなたの質問からすると、あなたの側に誤解があります。
Volatileあなたが説明するように、キーワードはキャッシュとは関係ありません。

キーワードvolatileが変数に指定されている場合、この変数はプログラムの他の部分から予期せず変更される可能性があるため、特定の最適化を行わないようにコンパイラーにヒントを与えます。

ここで意味することは、コンパイラは既にレジスタにロードされている値を再利用すべきではなく、レジスタの値がメモリに格納されている値と同じであることが保証されていないため、メモリに再度アクセスする必要があるということです。

キャッシュメモリに関する残りの部分は、プログラマーには直接関係ありません。

つまり、CPU のキャッシュ メモリと RAM の同期は、まったく別のテーマです。

于 2011-10-24T07:26:58.457 に答える
7

私の提案は、仮想メモリ マネージャーによってページを非キャッシュとしてマークすることです。
Windows では、これは をPAGE_NOCACHE呼び出すときの設定によって行われますVirtualProtect

多少異なる目的のために、SSE 2命令には_mm_stream_xyzキャッシュ汚染を防ぐための命令がありますが、ここではあなたのケースには当てはまらないと思います.

どちらの場合でも、C でやりたいことを移植できる方法はありません。OS 機能を使用する必要があります。

于 2011-10-24T06:59:48.453 に答える
2

ウィキペディアには、x86 ファミリの CPU に適用されるMTRR (Memory Type Range Registers) に関するかなり良い記事があります。

要約すると、Pentium Pro Intel (および AMD がコピーしたもの) から始まるこれらの MTR レジスタは、メモリの範囲に非キャッシュ、ライトスルー、ライトコンバイン、ライトプロテクト、またはライトバック属性を設定できます。

Pentium III から始めましたが、私が知る限り、実際には 64 ビット プロセッサでのみ有用であり、MTRR を尊重しますが、CPU がメモリの各ページのメモリ タイプを設定できるようにするページ属性テーブルによってオーバーライドできます。

私が知っている MTRR の主な用途は、グラフィックス RAM です。書き込み結合としてマークする方がはるかに効率的です。これにより、キャッシュが書き込みを保存できるようになり、すべてのメモリ書き込み順序規則が緩和されて、グラフィックス カードへの非常に高速なバースト書き込みが可能になります。

しかし、あなたの目的のためには、キャッシュされていないかライトスルーのいずれかの MTRR または PAT 設定が必要です。

于 2011-10-24T07:27:45.430 に答える
0

あなたが言うように、キャッシュはプログラマーに対して透過的です。システムは、そのアドレスを介してオブジェクトにアクセスした場合に、最後に書き込まれた値が常に表示されることを保証します。廃止された値がキャッシュにある場合に発生する可能性がある「唯一の」ことは、実行時のペナルティです。

于 2011-10-24T07:36:35.507 に答える
0

_Uncached キーワードを使用すると、MQX などの組み込み OS で役立つ場合があります

#define MEM_READ(addr)       (*((volatile _Uncached unsigned int *)(addr)))
#define MEM_WRITE(addr,data) (*((volatile _Uncached unsigned int *)(addr)) = data)
于 2012-12-17T21:59:28.267 に答える
0

volatileCPU とメモリ間のキャッシュに煩わされることなく、データが必要になるたびに読み取られるようにします。ただし、キャッシュされたデータではなくメモリから実際のデータを読み取る必要がある場合は、次の 2 つのオプションがあります。

  • 上記のデータがキャッシュされていないボードを作成します。何らかの I/O デバイスに対処する場合、これはすでに当てはまる可能性があります。
  • キャッシュをバイパスする特定の CPU 命令を使用します。これは、可能性のある SEU エラーをアクティブにするためにメモリをスクラブする必要がある場合に使用されます。

2 番目のオプションの詳細は、OS や CPU によって異なります。

于 2011-10-24T07:52:33.210 に答える