3

これは、私が現在維持しているいくつかのコードの簡略化されたバージョンです。

int SomeFunc() 
{
  const long lIndex = m_lCurrentIndex;
  int nSum = 0;
  nSum += m_someArray[lIndex];
  nSum += m_someArray[lIndex];
  return nSum;
}

lCurrentIndex は別のスレッドによって定期的に更新されます。質問は; m_CurrentIndex のローカル コピーを作成すると、m_someArray への両方のアクセスで同じインデックスが使用されるようになりますか?

これは単純化された例であることに注意してください。ここに示されている正確なコードではなく、ローカル コピーを作成するという概念について考えています。コンパイラが値をレジスタに入れることはわかっていますが、lCurrentIndex から 2 回読み取るのとは対照的に、それは依然としてローカル コピーです。

ありがとう!

編集: 最初の割り当ては安全です。セットアップでは両方とも 32 ビットであることが保証されています。Edit2:そして、それらは32ビット境界に正しく配置されています(それを忘れていました)

4

7 に答える 7

15

いいえ、共有変数を読み取るローカルの初期化は、必ずしもアトミックではありません。(たとえば、8 ビット プラットフォームで必要なコードを考えてみてください) 一般に、スレッド セーフなコードを記述する唯一の方法は、コンパイラや OS で指定されたアトミック操作を使用するか、OS のロック機能を使用することです。

于 2009-07-28T08:05:39.200 に答える
6

m_CurrentIndex のローカル コピーを作成すると、m_someArray への両方のアクセスで同じインデックスが使用されるようになりますか?

もちろん、同じ実行でSomeFunc、はい。ローカル整数変数 ( lIndex) は、関数の途中でその値を魔法のように変更することはありません。

もちろん、次のことも当てはまります。m_someArray[lIndex]( の値ではなくlIndex) の実際の値は変わる可能性があります。m_someArray自体が変更される可能性があります。そしてニールがlIndexの初期値の妥当性について言ったこと

于 2009-07-28T08:03:46.570 に答える
3

これはスレッド セーフである必要があります (少なくとも、私が使用したすべてのコンパイラ/OS ではそうです)。m_lCurrentIndexただし、二重に確認するために、 として宣言できますvolatile。その後、コンパイラはいつでも変更される可能性があることを認識します。

于 2009-07-28T08:57:11.563 に答える
3

はい、現在のインデックスのコピーにより、両方の配列アクセスが同じインデックスを使用するようになります。ただし、それは私が「スレッドセーフ」と考えていたものではありません。共有変数への同時アクセスに注意する必要があります。私には、配列へのアクセスも潜在的な懸念の領域になる可能性があるように見えます。

于 2009-07-28T08:04:32.417 に答える
1

ここで尋ねるべきもう 1 つの質問は、次のとおりです。コピー操作はm_lCurrentIndexアトミックlIndex操作ですか? そうでない場合は、おそらく何の役にも立たない非常に奇妙な値を使用してしまう可能性があります。:)

要点: 複数のスレッドを使用している場合、ある種のロックや同期を回避する方法はありません。

于 2009-07-28T08:06:48.857 に答える
0

はい、配列の同じ要素にアクセスします。m_lCurrentIndex の値のスナップショットをローカル変数に取り込んでいるようなものです。ローカル変数には独自のメモリがあるため、m_lCurrentIndex に対して何を行っても、ローカル変数には影響しません。ただし、割り当て操作がアトミックであることが保証されていないため、lIndex で無効な値になる可能性が非常に高いことに注意してください。これは、あるスレッドから m_lCurrentIndex を更新し、同時に他のスレッドから lIndex への代入を試みた場合に発生します。

于 2009-07-28T08:06:02.693 に答える