アトミック操作を行くsync.atomic

 

sync.atomic

提供される原子アトミック操作は、いくつかの単純なタイプの一方のみがアトミックロック操作の大量の使用を回避することができるプログラムで発生し、アトミック操作が操作されたゴルーチン一度に確保することができます。
これらのタイプは、INT32、Int64型、UINT32、UINT64、含む uintptr、unsafe.Pointer、 6の合計。
これらのアトミック機能5つの操作があります。さまざまな機能を提供増減比較して、スワップ、ロード、ストアおよび交換が。

アトミック一般的な操作は以下のとおりです。

  • 増減
  • 積載
  • 比較とスワップ
  • 為替
  • メモリ

 

増減

原子は、操作の値を増減する増減を実現することができます。こうしてオペランドの値のみ動作タイプ。
増加または減少する接頭辞を「追加」、および特定の種類の名前のために続くためにアトミック操作を実行するために使用されています。
パッケージには、以下の原子接頭辞に追加または削除操作を提供します:
- FUNC AddInt32(ADDR *のInt32、のInt32デルタ)(新新のInt32)
- FUNC AddInt64(ADDR *のInt64、Int64型デルタ)(新新Int64型)
- FUNC AddUint32(ADDR UINT32 *、デルタUINT32)(新新UINT32)
- FUNC AddUint64(ADDR * UInt64型、UInt64型デルタ)(新新UInt64型)
- FUNC AddUintptr(ADDR * UIntPtr、デルタUIntPtr)(新新UIntPtr)

例:

パッケージメイン
インポート(
    "FMT"
    「同期/アトミック」
    "時間"

FUNCのmain(){
   VAR optsのint64型= 0

   iについて:= 0; I <50; I ++ {
       //なお、第1引数の必須アドレス
       atomic.AddInt64(&OPTS、3)// add操作
       //atomic.AddInt64(&opts、-1)減算動作
       time.Sleep(time.Millisecond)
   }
   time.Sleep(time.Second)

   fmt.Println( "OPTS:"、atomic.LoadInt64(&optsの))
}

我々は、値が操作され減少する負の値を通過することができないように、第2関数のパラメータとatomic.AddUint64 atomic.AddUint32ための機能は、UINT32とUINT64です。まあ、これは私たちが、原子UINT32またはそれのuint64型の型の値を小さくすることができないことを意味するものではありませんか?幸いなことに、ではありません。我々は、この目的を達成するために回り道を提供することができますなどの言語を移動します。
私たちは型UINT32の変数の値の原子にしたい場合はNN(NNは負の整数を示す)を大きくui32、我々はatomic.AddUint32関数を呼び出すことができます。

atomic.AddUint32(&ui32、^ UINT32(-NN-1))

uint64型の値については、それもまた真実です。呼び出し式

atomic.AddUint64(&ui64、^ uint64型(-NN-1))

原子は、可変型UINT64の値がNNを増加(または-NNを減少させる)ui64表します。
それは2の補数の性質を利用していますので、このアプローチは、働くことができる理由。当社は、取得した否定(符号ビットを除く)、それにより、2の補数の負の整数ビットということと、コードを追加します知っています。我々はまた、一緒に2の補数のバイナリ値整数負のは、それが示される絶対値の還元によって得ることができることを知っています。例えば、式その後、NNは、int型の変数であり、その値が-35である場合

UINT32(INT32(NN))

^ UINT32(-NN-1)

結果は、11111111111111111111111111011101上の値になります。したがって、我々は^ UINT32(-NN-1)及び^ UINT64(-NN-1)を使用し、それぞれのコースのタイプUINT32とUINT64型NN物質を表します。このように、我々は合理的なタイプUINT32と値の種類に制限がuint64型バイパスすることができます。
これらは、一般的なソリューションを提供する公式のです。

積載

パッケージには、増減プレフィックス負荷にアトミック操作を提供します。

- FUNC LoadInt32(ADDR * INT32)(ヴァルINT32)

- FUNC LoadInt64(ADDR * int64型)(ヴァルint64モード)

- FUNC LoadPointer(ADDR * unsafe.Pointer)(ヴァルunsafe.Pointer)

- FUNC LoadUint32(ADDR * UINT32)(ヴァルUINT32)

- FUNC LoadUint64(ADDR * uint64型)(ヴァルUINT64)

- FUNC LoadUintptr(ADDR * uintptr)(ヴァルuintptr)

ローディング動作は、変数の値が原子を読み取るためにことを保証するために、他のCPUが読み取るとの根本的なハードウェア実装機構によって支持されている変数の書き込み操作ができない場合に読み取ります。
例:

V:= atomic.LoadInt32(&値)

Atomic.LoadInt32関数は、ポインタ値* INT32タイプを受け付け、ポインタ値のポイントの値を返します。

比較とスワップ

そして、スワップ操作英語のタイトル--compareとスワップは、CASと呼ばれます。同期/原子パッケージにおいて、名称「コンペア・アンド・スワップ」プレフィックス機能によって、そのような原子の操作が数を表します。
この操作は、CAS(コンペア・アンド・スワップ)と呼ばれています。コンペア・アンド・スワップなどの操作を接頭辞:

- FUNC CompareAndSwapInt32(ADDR * INT32、古い、新しいINT32)(スワップブール値)

- FUNC CompareAndSwapInt64(ADDR * int64型、古い、新しいint64型)(スワップブール値)

- FUNC CompareAndSwapPointer(ADDR * unsafe.Pointer、古い、新しいunsafe.Pointer)(スワップブール値)

- FUNC CompareAndSwapUint32(ADDR * UINT32、古い、新しいUINT32)(スワップブール値)

- FUNC CompareAndSwapUint64(ADDR * uint64型、古い、新しいuint64型)(スワップブール値)

- FUNC CompareAndSwapUintptr(ADDR * uintptr、古い、新しいuintptr)(スワップブール値)

この前提の下で為替操作する前に、古いパラメータ、会うの記録された値のまま必ず変数の交換価値を作る前の動作が変更されていないまずメイク、。CASの一般的な練習時に楽観的ロック機構同様の操作データベース。

ある場合、変数の多くは、読みゴルーチンと書き込み操作は、CASの動作になることがあり、という注意が成功しなかった、そして我々はループのために多くの時間を使用しようとすることができます。

例:

CompareAndSwapInt64機能は3つのパラメータを取ります。最初のパラメータはポインタ値が演算された値であるべきです。この値は、* int64型のタイプです。2種類のパラメータの後のint64タイプです。これらの値は、それぞれ古い値と新しい値に代わって動作させる必要があります。関数がCompareAndSwapInt64呼び出された後の最初の古い動作値が等しいパラメータのパラメータ値をADDRによって指されているか否かを判定する。この判断は肯定的な結果を得た後、新しい関数は古い元の値を置き換える新しいのを表すパラメータの値を使用します。それ以外の場合は、交換作業は後に無視されます。これは、この句の「比較とスワップ」の原点です。CompareAndSwapInt64機能スワップ結果は交換作業のか否かの値を示すために使用されます。

VaRの値int64モード

FUNC atomicAddOp(TMPのInt64){
にとって {
       OLDVALUE:=値
       atomic.CompareAndSwapInt64 IF(&値、OLDVALUE、OLDVALUE + TMP){
           リターン
       }
   }
}

ロックと比較すると、CASの操作は大きく異なります。常に演算値(すなわち、古い値に等しい)を変更し、この仮定は直ちに置き換え値の真正性を確認するであろう一度していないと想定されます。ロックの使用は、より慎重なアプローチです。我々は常にそこ動作値を変更するための同時操作で、それらを保護するために重要な領域にロック関連の操作を使用すると仮定します。私たちは、ロックを使用しての練習は悲観的になる傾向がありますが、CAS操作の練習はより楽観的であると言うことができます。

重要な領域と作成されたミューテックスを形成することなく、セキュリティの同時動作の値を置き換えるために行うことができCAS操作の利点。これは、大幅にプログラムのパフォーマンスの同期の損失を低減することができます。もちろん、CAS操作と欠点。値が頻繁に変更されて動作させた場合には、CASの操作が成功するのは簡単ではありません。

いくつかのタイプが値の、私たちは常にCAS操作を好む必要があります(具体的には、上記6つのタイプがあることと言う)同時更新を確保したいときに、覚えておいてください。

為替

スワップにこのような操作を接頭辞:

- FUNC SwapInt32(ADDR * INT32、新しいINT32)(旧INT32)

- FUNC SwapInt64(ADDR *のint64、int64型新)(旧int64モード)

- FUNC SwapPointer(ADDR * unsafe.Pointer、新しいunsafe.Pointer)(旧unsafe.Pointer)

- FUNC SwapUint32(ADDR * UINT32、新しいUINT32)(旧UINT32)

- FUNC SwapUint64(ADDR * uint64型、新uint64型)(旧UINT64)

- FUNC SwapUintptr(ADDR * uintptr、新しいuintptr)(旧uintptr)

CASに関しては、明らかにこのタイプの操作は、より直接的な暴力である、と関係なく、変数の古い値が変更されたかどうかの、戻り値に直接与えられた新しい値は当時置き換えます。

 

メモリ

店舗などの操作を接頭辞:

- FUNC StoreInt32(ADDR * INT32、ヴァルINT32)

- FUNC StoreInt64(ADDR *のint64、int64型のval)

- FUNCのStorePointer(ADDR * unsafe.Pointer、ヴァルunsafe.Pointer)

- FUNC StoreUint32(ADDR * UINT32、ヴァルUINT32)

- FUNC StoreUint64(ADDR * uint64型、ヴァルUINT64)

- StoreUintptr FUNC(ADDR * uintptr、ヴァルuintptr)

このような操作は、書き込み変数のアトミック性を確保するため、他の運転変数は、ダーティデータ修正処理を読んで避けます。

 

 

出典:

「並行プログラミングの戦闘GO」 - アトミック操作

アトミック操作を行きます

おすすめ

転載: www.cnblogs.com/-wenli/p/12380075.html