18

整数へのポインタがあるとしましょう。

volatile int* commonPointer = new int();

そして、そのポインターを逆参照する複数のスレッドがあります。

int blah = *commonPointer;

ただし、1 つのスレッドでそのポインターのアドレスを変更する必要があります。

int* temp = new int();
int* old = commonPointer;
InterlockedExchange(&commonPointer,temp);
delete old;

さて、一部のスレッドが「古い」値を読み取っている可能性があり、一部のスレッドが「新しい」値を読み取っている可能性があるという事実を無視しましょう。これは私の場合は問題ではありません。

アドレスが削除されるのと同じように、1 つのスレッドがポインターの逆参照を開始し、例外を取得するシナリオはありますか?
それとも、逆参照は十分にアトミックなので、それは起こりませんか?

4

4 に答える 4

22

この場合、C++ 標準では原子性を保証するものは何もありません。

関連するコード領域をミューテックスで保護する必要がありstd::atomicます。ポインターへのアトミックアクセスのみを提供するだけで十分ではありませんが、逆参照操作は含まれません。

于 2013-05-20T07:29:30.377 に答える
3

まず、volatile宣言の には実際の効果はありません。次に、1 つのスレッドで値を変更し、複数のスレッドでその値にアクセスするとすぐに、すべてのアクセスを保護する必要があります。そうしないと、未定義の動作になります。どのような保証が得られるかはわかりません InterlockedExchangeが、それを呼び出さないスレッドには影響がないことは確かです。

于 2013-05-20T08:12:53.807 に答える
1

Edit2: 申し訳ありませんが、役に立ちません。アクセスの周りにミューテックスが必要です-コンパイラが生成したコードがポインタをレジスタ[またはレジスタのないプロセッサの場合はスタックなどの他のストレージ]にロードし、ポインタが指すメモリにアクセスする可能性があります(非常に可能性が高い)同時に、ポインターは別のスレッドによって更新されています。ポインターが正しいことを保証する唯一の方法は、ミューテックスまたは同様の構造を使用して、アクセスのブロック全体を閉じることです。それ以外は失敗する可能性があります。

syam が言うように、標準では、ポインターが指す 32 ビット値の読み取りでさえアトミックであることを保証していません。それはシステムの実装に依存しています。ただし、「古い値または新しい値のいずれかの値を取得できますか」という質問がある場合は、少なくとも x86 および x86-64 がそれを保証します。他のマシン アーキテクチャではそうではない可能性があります (SMP 68000 プロセッサでの 32 ビット int 実装では保証されません。書き込みは一度に 16 ビットであり、2 番目のプロセッサがその半分を書き込んでいる可能性があるためです)。 68000 プロセッサを搭載した SMP システムが構築されていることは知っています)。

( InterlockedExchange「標準」関数ではない) は、このスレッドのプロセッサがポインタ自体に排他的にアクセスできることを保証するため、安全に実行できます。他のプロセッサはその時点でポインタにアクセスできません。これが、x86 アーキテクチャの「ロックされた」命令の要点です。それらは「安全」です (かなり遅いですが、毎回これを実行しないと仮定すると...)。

commonPointer編集:コンパイラは、別のスレッドを使用して更新していることを認識しない可能性があるため、それ自体に注意する必要があることに注意してください。そのため、まだ OLD ポインター値から読み取っている可能性があります。

[何もインライン化されていない]関数への呼び出し、またはポインターの宣言はvolatile int * volatile commonPointer;、そのトリックを行う必要があります。[「誰かが以前に投稿したようvolatileに解決策がある問題はないので、を使用するための私の答えに反対票を投じる人をキューに入れます]。volatile

[上記の edit2 を参照]

于 2013-05-20T07:45:19.567 に答える