6

ビットフィールドがコンパイラに依存することは知っていますが、最新の g++ および Visual C++ 2010 を使用したビットフィールドのスレッド セーフに関するドキュメントは見つかりませんでした。

ビットフィールドメンバーの操作はアトミックですか?

4

5 に答える 5

6

残念ながら、「スレッドセーフ」は、プログラミングでは非常に過負荷な用語です。

ビットフィールドへのアトミックアクセスを意味する場合、答えはノーです(少なくとも私が知っているすべてのプロセッサで)。32 ビット マシンでは 32 ビットのメモリ ロケーションにアトミックアクセスできますが、それは 32 ビット値全体を読み書きすることを意味するだけです。これは、別のスレッドが同じことをしないという意味ではありません。停止しようとしている場合は、同期が必要になる可能性があります。

ビットフィールドへの同期アクセスを意味する場合、アクセスをより高いレベルの同期プリミティブ (アトミック操作で構築されることが多い) でラップしない限り、答えもノーです。

要するに、コンパイラは、追加の作業なしではビット フィールドへのアトミックアクセスまたは同期アクセスを提供しません。

それは役に立ちますか?

編集: Dan Grossman 博士は、UOregon の CS 部門のページで見つけた原子性と同期に関する 2 つのすばらしい講義を行っています

于 2011-05-31T19:51:42.183 に答える
4

ビットフィールドに書き込むとき、別のスレッドが同じ構造内の任意の (同じまたは異なる) ビットフィールドにアクセス (読み取りまたは書き込み) しようとすると、未定義の動作が発生する時間ウィンドウが存在する場合があります。起こる。ビット フィールドを読み取る場合、別のスレッドが同じ構造体のビット フィールドに書き込もうとすると、未定義の動作が発生するタイム ウィンドウが存在する場合があります。

問題のビットフィールドに個別の変数を実際に使用できない場合は、複数のビットフィールドを整数に格納し、ビットフィールド構造と 32 ビット整数の間の和集合を作成することで、それらをアトミックに更新できる場合があります。次に、CompareExchange シーケンスを使用します。

  1. ビットフィールドの値を Int32 として読み取ります。
  2. それをビットフィールド構造に変換します
  3. 構造を更新する
  4. 構造体を Int32 に変換します。
  5. (1) で読み取った値をまだ保持している場合にのみ、CompareExchange を使用して変数を新しい値で上書きします。値が変更された場合は、手順 (1) からやり直してください。

このアプローチがうまく機能するには、ステップ 2 ~ 4 が高速である必要があります。時間がかかるほど、手順 5 の CompareExchange が失敗する可能性が高くなるため、CompareExchange が成功するまでに手順 2 ~ 4 を再実行する必要がある回数が増えます。

于 2011-05-31T20:16:49.030 に答える
1

スレッドセーフな方法でビットフィールドを更新する場合は、ビットフィールドを個別のフラグに分割し、通常intのsを使用してそれらを格納する必要があります。個別のマシンワードへのアクセスはスレッドセーフです(ただし、マルチプロセッサシステムでの最適化とキャッシュコヒーレンシを考慮する必要があります)。

于 2011-05-31T19:40:35.273 に答える
1

Windows連動機能を見る

この関連するSOの質問も参照してください

于 2011-05-31T19:50:01.293 に答える
0

シンプルにatomic.AddInt32の例を使用してください:

atomic.AddInt32(&intval, 1 << 0)      //set the first bit
atomic.AddInt32(&intval, 1 << 1) //set the second bit
atomic.AddInt32(&intval, -(1 << 1 + 1 << 0)) //clear the first and second bit

コードは Go にあります。C++ には、atomic.AddInt32 のようなものもあると思います。

于 2012-10-28T02:11:29.957 に答える