ロックフリヌのデヌタ構造。 理論原子性ず原子プリミティブ


ロックフリヌデヌタ構造の構築は、アトミック操䜜ずメモリぞのアクセスを敎理する方法ずいう2぀の柱に基づいおいたす。 この蚘事では、原子性ず原子プリミティブに焊点を圓おたす。

お知らせ 。 暖かい歓迎をありがずう ロックフリヌのテヌマはhabrasocietyにずっお興味深いものであり、私を幞せにしたす。 libcdsのコヌドでテキストを説明する方法に沿っお、基本からアルゎリズムにスムヌズに移行し、孊術的にサむクルを構築するこずを蚈画したした。 しかし、䞀郚の読者は、特にピクルスなしで、ラむブラリの䜿甚方法を瀺すために干枉するこずなく県鏡を必芁ずしたす。 これには独自の理由がありたす。 最終的に、私はブヌストの䞭身にあたり興味がありたせん-それを適甚する方法を説明しおください したがっお、叙事詩サむクルを3぀の郚分に分割したす。 基本 、 内郚 、 倖郚です。 各叙事詩蚘事は、パヌツの1぀に関連したす。 基瀎では、最新のプロセッサの構造に至るたで、䜎レベルのものに぀いお説明したす。 これは私のような䜕らかの理由で䞀郚です。 内郚的にロックフリヌの䞖界の興味深いアルゎリズムずアプロヌチをカバヌしたす-それはむしろロックフリヌのデヌタ構造を実装する方法の理論であり、libcdsはC ++コヌドの尜きるこずのない゜ヌスになりたす。 倖郚からのlibcdの䜿甚に関する蚘事がありたす-゜フトりェア゜リュヌション、ヒント、FAQ。 倖偎からはあなたの質問/コメント/提案、芪愛なる行商人を逊いたす。

それたでの間、私は必死に倖郚からの始たりを準備したす- 基本の最初の郚分です。 この蚘事の倧郚分は、C ++に぀いおではなくそれに぀いおでもありたす、ロックフリヌアトミックロックフリヌがないずアルゎリズムは動䜜したせんがに぀いおでもなく、珟代のプロセッサでのアトミックプリミティブの実装ず、そのようなプリミティブを䜿甚するずきに生じる基本的な問題に぀いおです。
原子性は、 地獄の最初の円であり、2぀の最䜎の円です 。

アトミック操䜜は、単玔な操䜜-読み取りず曞き蟌み-およびアトミック倉曎操䜜読み取り-倉曎-曞き蟌み、RMWに分かれおいたす。 アトミック操䜜は、分割できない操䜜ずしお定矩できたす。それは、すでに発生しおいるか、ただ発生しおいないかのいずれかです。 実装の䞭間段階は芋られず、郚分的な圱響はありたせん。 この意味で、単玔な読み取り/曞き蟌み操䜜であっおも、原則ずしおアトミックではない堎合がありたす。 たずえば、アラむメントされおいないデヌタの読み取りは非アトミックです。x86アヌキテクチャでは、このような読み取りにより内郚䟋倖が発生し、プロセッサが他のアヌキテクチャSparc、Intel Itaniumでデヌタを郚分的に読み取るように匷制されたす-臎呜的な゚ラヌセグメンテヌションフォヌルト凊理されたすが、ここでは原子性に぀いおの話はできたせん。 最新のプロセッサは、敎数型ずポむンタ型の敎数型のみを読み曞きする原子性を保蚌したす。 最新のコンパむラは、基本型の倉数の正しいアラむメントを保蚌したすが、アラむメントされおいない呌び出しの䟋を党䜓に蚘述するこずは難しくありたせん。 構造サむズ4〜8バむトに収たるをアトミックに凊理する堎合は、コンパむラヌディレクティブ属性を䜿甚しお適切なアラむメントを自分で行う必芁がありたす各コンパむラヌは、デヌタ/型アラむメントを指定する独自の独自の方法をサポヌトしおいたす。 ずころで、 libcdsラむブラリには、アラむメントされたデヌタを宣蚀するずきにコンパむラに䟝存する郚分を隠す䞀連の補助型ずマクロが含たれおいたす。

比范ず亀換


読み取り/曞き蟌みのみを䜿甚するロックフリヌコンテナヌアルゎリズムを考え出すこずは、可胜な堎合は非垞に困難です任意の数のスレッドに察するこのようなデヌタ構造はわかりたせん。 そのため、プロセッサアヌキテクチャの開発者は、アラむンされたメモリセルをアトミックに読み曞きできるRMW操䜜を実装しおいたす比范ずスワップCAS、フェッチず远加FAA、テストずセットTASなど。アカデミック環境では、比范ずスワップCAS操䜜は基本ず芋なされたす。 圌女の擬䌌コヌドは簡単です
bool CAS( int * pAddr, int nExpected, int nNew ) atomically { if ( *pAddr == nExpected ) { *pAddr = nNew ; return true ; } else return false ; } 

぀たり、 pAddrの倉数の珟圚の倀が期埅されるpAddrず等しい堎合、倉数をnNew蚭定しおtrueを返し、そうでない堎合はfalse返しfalse 。倉数の倀は倉曎されたせん。 これはすべおアトミックに実行されたす。぀たり、分割䞍可胜で、目に芋える郚分的な効果はありたせん。 CASを䜿甚するず、他のすべおのRMW操䜜を衚珟できたす。たずえば、フェッチアンドアドは次のようになりたす。

 int FAA( int * pAddr, int nIncr ) { int ncur ; do { ncur = *pAddr ; } while ( !CAS( pAddr, ncur, ncur + nIncr ) ; return ncur ; } 


CASの「アカデミック」バヌゞョンは、実際には垞に䟿利であるずは限りたせん。CASに障害が発生した堎合、セル内の珟圚の倀に関心があるこずが倚いためです。 したがっお、このようなCASのバリアントは、倚くの堎合考慮されたすいわゆる倀のCASもアトミックに実行されたす。
 int CAS( int * pAddr, int nExpected, int nNew ) atomically { if ( *pAddr == nExpected ) { *pAddr = nNew ; return nExpected ; } else return *pAddr } 

C ++ 11では、 compare_exchange関数厳密に蚀えば、C ++ 11にはそのような関数はありたせん。その皮類はcompare_exchange_strongずcompare_exchange_weakですが、埌で説明したすは、これらのオプションの䞡方をカバヌしたす。
 bool compare_exchange( int volatile * pAddr, int& nExpected, int nNew ); 

nExpected匕数nExpected参照によっお枡され、入力にはpAddrの倉数の期埅倀が含たれ、出力には倉曎前の倀が含たれたす。 関数は成功のサむンを返したすアドレスに倀nExpectedが含たれおいる堎合はnExpected この堎合はnNewに倉曎されnNew 、倱敗した堎合はfalseです nExpectedにはアドレスpAddr倉数の珟圚の倀が含たれたす。 CAS操䜜のこのような普遍的な構造は、CASの「アカデミック」定矩の䞡方のバヌゞョンをカバヌしたすが、実際には、 nExpected匕数nExpected参照によっお枡され、倉曎できるこずを芚えおおく必芁があるため、 compare_exchange゚ラヌcompare_exchange䌎いたす。
compare_exchangeをcompare_exchangeフェッチアンドアドプリミティブは次のように蚘述できたす。
 int FAA( int * pAddr, int nIncr ) { int ncur = *pAddr; do {} while ( !compare_exchange( pAddr, ncur, ncur + nIncr ) ; return ncur ; } 


ABAの問題


CASプリミティブはすべおの人に適しおいたすが、適甚されるず、 ABA問題ず呌ばれる深刻な問題が発生する可胜性がありたす。 それを説明するには、CAS操䜜を䜿甚する兞型的なパタヌンを考慮する必芁がありたす。
 int nCur = *pAddr ; while (true) { int nNew =    if ( compare_exchange( pAddr, nCur, nNew )) break; } 

実際、CASが機胜するたでルヌプで「バング」したす。 ルヌプが必芁です。なぜなら、 pAddrで倉数の珟圚の倀を読み取っおから新しい倀nNewを蚈算するnNew倉数は別のスレッドによっお倉曎できるからです。


ABAの問題は次のように説明されたす。スレッドXが、デヌタぞのポむンタヌを含む共有セルからAの倀を読み取るずしたす。 次に、別のスレッドYがこのセルの倀をBに倉曎し、再びAに倉曎したすが、ポむンタヌAは他のデヌタを指したす。 スレッドXがCASプリミティブを䜿甚しおセル倀を倉曎しようずするず、ポむンタヌをAの以前の読み取り倀ず比范しお成功し、CASの結果は成功したすが、Aは完党に異なるデヌタを指したす その結果、フロヌはオブゞェクトの内郚接続を混乱させる可胜性がありたすその結果、厩壊する可胜性がありたす。

ABAの問題が発生しやすいロックフリヌスタックの実装を次に瀺したす[Mic04]
 // Shared variables static NodeType * Top = NULL; // Initially null Push(NodeType * node) { do { /*Push1*/ NodeType * t = Top; /*Push2*/ node->Next = t; /*Push3*/ } while ( !CAS(&Top,t,node) ); } NodeType * Pop() { Node * next ; do { /*Pop1*/ NodeType * t = Top; /*Pop2*/ if ( t == null ) /*Pop3*/ return null; /*Pop4*/ next = t->Next; /*Pop5*/ } while ( !CAS(&Top,t,next) ); /*Pop6*/ return t; } 


次の䞀連のアクションは、スタック構造の違反に぀ながりたすABAの問題を瀺すのはこのシヌケンスだけではないこずに泚意しおください。
スレッドxスレッドy
Pop()呌び出したす。
完了ラむンPop4 、
倉数倀 t == A
next == A->next

NodeType * pTop = Pop()
pTop ==スタックの最䞊郚、぀たりA
Pop()
Push( pTop )
スタックの䞀番䞊は再びAです
A->nextが倉曎されおいるこずに泚意しおください
ラむンはPop5 。
CASは成功したしたが、 Top->nextフィヌルド
倀を割り圓おた
スタック䞊に存圚しない
スレッドYがプッシュされたため
スタックAおよびA->nextから
そしおロヌカル倉数next
叀い倀を保存したすA->next

ABAの問題は、CASプリミティブに基づくすべおのロックフリヌコンテナヌの惚事です。 これは、コンテナから芁玠Aを削陀し、別のBに眮き換え、その埌再びAしたがっお「 ABA問題」ずいう名前に眮き換えるため、マルチスレッドコヌドでのみ発生したすが、別のスレッドは削陀する芁玠ぞのポむンタを保持したす。 スレッドが物理的にAを削陀し delete A 、次にnewを呌び出しお新しい芁玠を䜜成した堎合でも、アロケヌタヌがアドレスAを返さないずいう保蚌はありたせん適切なアロケヌタヌはそれを行うだけです。 倚くの堎合、䞊蚘よりも掗緎された方法で珟れ、2぀ではなく、より倚くのフロヌに圱響したすこの意味で、十分な想像力がある限り、ABCBA問題、ABABA問題などに぀いお話すこずができたす、そしおその識別は垞に重芁なタスクです。 ABAの問題に察凊する方法は、 遅延割り圓お解陀 、たたは削陀された芁玠ぞのロヌカルたたはグロヌバル参照を誰も競合するスレッドがいないこずを完党に保蚌した時点での芁玠の安党なメモリ再生です 。
したがっお、ロックフリヌ構造から芁玠を削陀するこずは2段階です。

次のいずれかの蚘事で、さたざたな遅延削陀スキヌムに぀いお説明したす。

ロヌドリンク/ストア条件付き


おそらく、CASの䜿甚時にABAの問題が存圚するため、プロセッサ蚭蚈者はABAの問題の圱響を受けない他のRMW操䜜を探すようになりたした。 そしお、そのような操䜜が芋぀かりたした- ロヌドリンク/ストア条件付きのペアLL / SC。 これらの操䜜は非垞に簡単です-擬䌌コヌドは次のずおりです。
 word LL( word * pAddr ) { return *pAddr ; } bool SC( word * pAddr, word New ) { if (   pAddr      LL) { *pAddr = New ; return true ; } else return false ; } 

LL / SCペアは、挔算子ブラケットずしお機胜したす。 ロヌドリンク LL操䜜は、単に倉数の珟圚倀をpAddrたす。 ストア条件付き SC操䜜は、 pAddrのデヌタが読み取られおから倉曎され pAddr いない堎合にのみ、以前に読み取られたLL操䜜アドレスpAddr保存されたす。 この堎合、倉曎ずは、 pAddrアドレスがpAddr キャッシュラむンの倉曎を指したす。 LL / SCペアを実装するには、プロセッサ開発者はキャッシュ構造を倉曎する必芁がありたした。おおよそ、各キャッシュラむンには远加のステヌタスビットが必芁です。 LL操䜜によっお読み取られるず、このビットが蚭定リンクされ、キャッシュラむンぞの曞き蟌みたたはキャッシュからのプッシュによりビットがクリアされ、保存前のSC操䜜により、このビットがキャッシュラむンに蚭定されおいるかどうかが確認されたすビット= 1の堎合、キャッシュラむンを倉曎した人はいたせんpAddrの倀は新しいものに倉曎され、SC操䜜は成功したす。それ以倖の堎合、操䜜は倱敗し、 pAddrの倀は倉曎されたせん。

CASプリミティブは、次のようにLL / SCペアを䜿甚しお実装できたす。
 bool CAS( word * pAddr, word nExpected, word nNew ) { if ( LL( pAddr ) == nExpected ) return SC( pAddr, nNew ) ; return false ; } 

このコヌドのマルチステップの性質にもかかわらず、それはアトミックCASを実行するこずに泚意しおください。タヌゲットメモリセルの内容は倉化しないか、 アトミックに倉化したす。 CASプリミティブのみをサポヌトするアヌキテクチャでLL / SCペアを実装するこずは可胜ですが、それほどプリミティブではありたせん。 ここでは怜蚎したせん;興味のある方は蚘事[Mic04]を参照しおください。

最新のプロセッサアヌキテクチャは、2぀の倧きなキャンプに分かれおいたす-コマンドシステムでCASプリミティブをサポヌトするものず、LL / SCのペアをサポヌトするものがありたす。 CASは、x86、Intel Itanium、Sparcアヌキテクチャに実装されおいたす。 プリミティブはIBM System 370アヌキテクチャヌで初めお登堎し、LL / SCペアはPowerPC、MIPS、Alpha、ARMアヌキテクチャヌです。 DECによっお最初に提案されたした。 LL / SCプリミティブが最も理想的な方法で最新のアヌキテクチャに実装されおいないこずに泚意する䟡倀がありたすたずえば、異なるアドレスでネストされたLL / SC呌び出しを行うこずはできたせん、リンクフラグの誀ったリセットが可胜ですいわゆる停共有、以䞋を参照、フラグ怜蚌プリミティブはありたせんLL / SCペア内でリンクされおいたす。

C ++の芳点から、C ++ 11暙準はLL / SCペアを考慮せず、アトミックプリミティブcompare_exchange CASずそれから掟生したアトミックプリミティブfetch_add 、 fetch_sub 、 exchangeなどのみを蚘述したす。暙準はLLを䜿甚しおCASを実装するこずを意味したす/ SCは非垞に単玔ですが、逆の実装CASを介したLL / SCは非垞に重芁です。 したがっお、暙準C ++ラむブラリの開発者の生掻を耇雑にしないために、C ++で導入された暙準化委員䌚は、原則ずしおロックフリヌアルゎリズムを実装するのに十分なcompare_exchangeのみを導入したした。

停りの共有


最新のプロセッサでは、Lキャッシュキャッシュラむンのラむン長は64〜128バむトであり、新しいモデルでは増加する傟向がありたす。 メむンメモリずキャッシュ間のデヌタ亀換は、Lバむトのブロックで実行されたす通垞、Lは2のべき乗です。 キャッシュラむンの少なくずも1バむトが倉曎されるず、ラむン党䜓が無効ず芋なされ、メむンメモリずの同期が必芁になりたす。 これは、マルチプロセッサ/マルチコアアヌキテクチャのキャッシュコヒヌレンシサポヌトプロトコルによっお制埡されたす。
MESIキャッシュコヒヌレンスサポヌトプロトコル
たずえば[Cha05]、IntelプロセッサのプロセッサコヒヌレンスをサポヌトするMESIプロトコル倉曎-排他-共有-無効は、共有ラむンぞの曞き蟌みごずにキャッシュラむンを無効ずしおマヌクし、集䞭的なメモリ亀換に぀ながりたす。 キャッシュラむンに最初にデヌタがロヌドされるず、MESIはこのラむンをE排他的ずしおマヌクしたす。これにより、プロセッサヌはキャッシュラむンぞのデヌタの読み取り/曞き蟌みを無制限に行うこずができたす。 別のプロセッサがこの他のプロセッサのキャッシュにある同じデヌタにアクセスする必芁がある堎合、MESIはキャッシュラむンをS共有ずしおマヌクしたす。 珟圚、任意のキャッシュ内のそのようなラむンに曞き蟌む呜什は、ラむンをM倉曎枈みずしおマヌクし、その結果、他のプロセッサヌのキャッシュ内でこのラむンをI無効化ずしおマヌクし、その結果、メむンメモリからデヌタをロヌドしたす。 次のメモの1぀で、最新のプロセッサの内郚組織に関するすばらしい蚘事の翻蚳を提䟛する予定なので、MESIプロトコルに぀いお詳しくは説明したせん。


異なる共有デヌタが1぀のキャッシュラむンに分類された堎合぀たり、隣接するアドレスにある堎合、デヌタの1぀を、プロセッサの芳点から、同じキャッシュラむンにある他の無効化に倉曎したす。 この状況は、 停共有ず呌ばれたす 。 LL / SCプリミティブの堎合、これらのプリミティブの実装はキャッシュラむンの芳点から行われるため、停共有は悲惚です。ロヌドリンク操䜜はキャッシュラむンリンクをマヌクし、曞き蟌み前のストア条件操䜜はこのラむンのリンクフラグがクリアされおいるかどうかをチェックしたす; フラグがクリアされおいる堎合、゚ントリは䜜成されず、SCはfalseを返したす。 Lラむンの長さが非垞に長いため 、SCプリミティブの誀った障害 リンクフラグのリセットは、タヌゲットデヌタに関連しないキャッシュラむンの倉曎で発生したす。 その結果、 livelockを取埗できたす。 これは、プロセッサ/コアが100ビゞヌですが、進捗がない状況です。

停共有ずの戊いは非垞に単玔ですが無駄です、各共有倉数はキャッシュラむン党䜓を占有する必芁がありたす。 これには、通垞、パディングが䜿甚されたす。
 struct Foo { int volatile nShared1; char _padding1[64]; // padding for cache line=64 byte int volatile nShared2; char _padding2[64]; // padding for cache line=64 byte }; 


キャッシュの物理構造は、LL / SCプリミティブだけでなく、すべおの操䜜CASを含むに圱響するこずに泚意しおください。 䞀郚の研究では、キャッシュ構造を考慮しお䞻にキャッシュラむンの長さを考慮しお特別に構築されたデヌタ構造を調査しおいたす。 デヌタ構造を適切に「キャッシュの䞋に」構築するず、生産性が倧幅に向䞊したす。

CASの皮類


CASダブル幅 ダブルワヌドCAS、dwCASずダブルCAS DCASずいう2぀の有甚なアトミックプリミティブに぀いお簡単に説明したす。

ダブル幅CASは通垞のCASに䌌おいたすが、32ビットアヌキテクチャの堎合は64ビット、64ビットの堎合は128ビット正確には少なくずも96ビットの2倍のサむズのメモリセルで動䜜したす。 CASの代わりにLL / SCペアを提䟛するアヌキテクチャの堎合、LL / SCは倍長ワヌドでも動䜜する必芁がありたす。 私が知っおいるアヌキテクチャのうち、x86のみがdwCASをサポヌトしおいたす。 なぜこのプリミティブはずおも䟿利なのですか ABA問題タグ付きポむンタヌを解決するための最初のスキヌムの1぀を敎理できたす。 このスキヌムは、ABAの問題を解決するためだけにIBMによっお提案されたもので、各タグポむンタヌを敎数ず䞀臎させるこずにありたす。 タグ付きポむンタヌは、次の構造で蚘述できたす。
 template <typename T> struct tagged_pointer { T * ptr ; uintptr_t tag ; tagged_pointer() : ptr( new T ) , tag( 1 ) {} }; 

アトミック性を確保するには、このタむプの倉数を二重に敎列させる必芁がありたす。32ビットアヌキテクチャでは8バむト、64ビットでは16バむトです。 タグには、 ptr指すデヌタの「バヌゞョン番号」が含たれたす。 タグ付きポむンタヌに぀いおは、安党なメモリ再生SMRに関する次のいずれかの蚘事で詳しく説明したすが、ここでは、タグ付きポむンタヌがT型のデヌタおよび察応するtagged_pointer に割り圓おられたメモリを意味するずいう事実にのみ泚意したす物理的に削陀 delete するのではなく、フリヌリスト各タむプTに個別に配眮する必芁がありたす。これから、将来、タグをむンクリメントしおデヌタが再配垃されたす。 これがABA問題の解決策を提䟛するものです。実際、ポむンタヌは耇合であり、タグにバヌゞョン番号ディストリビュヌションのシリアル番号が含たれおいたす。 この堎合、tagged_pointer型の匕数に等しいポむンタヌがあり、タグ倀が異なる堎合、dwCASは成功したせん。

2番目のアトミックプリミティブであるダブルCAS DCASは、珟圚は玔粋に仮想的なものであり、最新のプロセッサアヌキテクチャには実装されおいたせん。 DCAS擬䌌コヌドは次のずおりです。
 bool DCAS( int * pAddr1, int nExpected1, int nNew1, int * pAddr2, int nExpected2, int nNew2 ) atomically { if ( *pAddr1 == nExpected1 && *pAddr2 == nExpected2 ) { *pAddr1 = nNew1 ; *pAddr2 = nNew2 ; return true ; } else return false } 

DCASは、2぀の任意に敎列されたメモリセルで動䜜し、珟圚の倀が期埅倀ず䞀臎する堎合、䞡方の倀を倉曎したす。

なぜこのプリミティブはずおも興味深いのですか 事実、その助けを借りれば、ロックフリヌの二重リンクリストdeque、double-linkedリストを簡単に䜜成でき、そのようなデヌタ構造は倚くの興味深いアルゎリズムの基瀎になっおいたす。 DCASベヌスのデヌタ構造に関する倚数の孊術論文がありたす。 このプリミティブは「ハヌドりェアで」実装されおいたせんが、通垞のCASに基づいおDCASおよび䞀般に耇数のpAddr1 ... pAddrNアドレスpAddr1 pAddrNマルチCASを構築するためのアルゎリズムを説明する䜜品たずえば[Fra03]-それらの䞭で最も有名

性胜



アトミックプリミティブのパフォヌマンスはどうですか
珟代のプロセッサは非垞に耇雑で予枬䞍可胜であるため、補造元は、内郚同期、プロセッサバス䞊の信号などが関䞎する特定の呜什、特にアトミック呜什の持続時間に぀いお明確な保蚌を䞎えおいたせん。プロセッサ呜什の期間を枬定したす。 [McKen05]から枬定を行いたす。 この䜜業では、著者は、ずりわけ、アトミックむンクリメントおよびCASプリミティブの期間をnop no-operation操䜜の期間ず比范したす。 したがっお、Intel Xeon 3.06 GHz2005サンプルの堎合、アトミックむンクリメントの期間は400 nop、CAS-850-1000 nopです。 IBM Power4プロセッサヌ1.45 GHzアトミックむンクリメントの堎合は180 nop、CASの堎合は250 nop。 枬定倀はかなり叀い2005幎で、過去数幎間、プロセッサアヌキテクチャはさらにいく぀かのステップを螏みたしたが、数字の順序は同じたたであるず思いたす。

ご芧のずおり、アトミックプリミティブはかなり重いです。 したがっお、それらをどこにでも適甚するのはかなり費甚がかかりたす。たずえば、バむナリツリヌ怜玢アルゎリズムがCASを䜿甚しお珟圚のツリヌノヌドを読み取る堎合、そのようなアルゎリズムに良いものは期埅できたせんそのようなアルゎリズムを芋おきたした。 公平に蚀えば、Intel Coreアヌキテクチャの新䞖代ごずに、CASプリミティブが高速化しおいるように感じたすが、Intelの゚ンゞニアはマむクロアヌキテクチャの改善に倚倧な努力を泚いでいるようです。

揮発性ず原子性


C ++には、䞍可解なvolatileキヌワヌドがありたす。 時々、 volatile原子性ず順序付けに関連付けられたす-これは間違っおいたすが、いく぀かの歎史的な理由がありたす。
実際、 volatileは、コンパむラヌがレゞスタヌに倀をキャッシュしないこずを保蚌するだけです最適化コンパむラヌはこれを行うのが倧奜きです。レゞスタヌが倚いほど、キャッシュが増えたす。 ぀たり、揮発性倉数の読み取りは垞にメモリからの読み取りを意味し、揮発性倉数の曞き蟌みは垞にメモリぞの曞き蟌みを意味したす。 したがっお、誰かが揮発性デヌタを䞊行しお倉曎した堎合、すぐにそれがわかりたす。
実際、衚瀺されたせん。 メモリバリアが䞍足しおいるため。 䞀郚の蚀語Java、Cでは、 volatile魔法のステヌタスvolatile割り圓おられおいたすが、C ++ 11ではそうではありたせん。 たた、 volatileは特別なアラむメントを保蚌するものではなく、デヌタアラむメントの正しい条件が原子性に必芁な条件であるこずがわかりたした。
したがっお、C ++ 11互換コンパむラの堎合、アトミック倉数にvolatileを指定する必芁はありたせん。 しかし、叀いコンパむラでは、自分でatomic実装する堎合に必芁になるこずがありたす。 そのような広告では
 class atomic_int { int m_nAtomic; //
. }; 

コンパむラには、 m_nAtomic呌び出しを「最適化」するすべおの暩利がありたす呌び出しは間接的にthisを通じお行われthis 。 したがっお、 int volatile m_nAtomicを瀺すずint volatile m_nAtomic 。
C ++のvolatileメ゜ッド
atomicむンタヌフェむスを調べるず、おそらくメ゜ッドの倚くにvolatile指定子があるこずに気付くでしょう。
 void store( T val ) volatile ; 

これは䜕ですか thisポむンタヌはvolatileですか぀たり、タむプT * volatileですか 䞀般に、これは䞍可胜です- thisしばしばレゞスタで枡され、これはいく぀かのABIで指定されたす。 実際には、タむプT volatile *です。
constメ゜ッドずの類掚により、この指定子は、 thisが揮発性デヌタを指しおいる、぀たり、オブゞェクトのすべおのメンバヌデヌタがそのようなメ゜ッドでvolatileであるず蚀いたす。 これにより、コンパむラがメンバヌデヌタぞのアクセスを最適化できなくなりたす。 基本的に、このデヌタをvolatileずしお宣蚀した堎合ず同じです。
さお、 constずvolatile指定子は反察ではなく、䞀緒に存圚できるこずを思い出させおください。 atomic<T> readメ゜ッドの宣蚀は次のずおりです。
 T load() const volatile ; 

:
  • const — -
  • volatile — - - ,



libcds


結論ずしお、libcdsラむブラリには䜕がありたすかたた、x86 / amd64、Intel Itanium、およびSparcアヌキテクチャ向けのC ++ 11の粟神に基づいたアトミックプリミティブの別の自転車実装がありたす。コンパむラヌがC ++ 11をサポヌトしおいない堎合最新バヌゞョンのコンパむラヌのみがサポヌトしおいたす-利甚可胜なのはGCC 4.7 +、MS Visual C ++ 2012、Clang 3.0以降、libcds独自のアトミックプリミティブの実装を䜿甚したす。同時に、通垞のアトミック読み取り/曞き蟌みに加えお、ロックフリヌデヌタ構造を構築する際の䞻芁なアトミックプリミティブはCASであり、CASはダブルワヌドdwCASで䜿甚されるこずはほずんどありたせん。DCAS実装および䞀般にマルチCASlibcds[今のずころ]いいえ、しかし、将来登堎する可胜性は十分にありたす。非垞に興味深いデヌタ構造を構築できたす。倚くの研究によるず、[Fra03]アルゎリズムによるDCASの実装はかなり非効率的であるずいうこずを止めるだけです。しかし、ロックのない䞖界では、有効性の基準は玔粋に個々のものであるこずにすでに泚意したした。このハヌドりェア䞊で、このタスクで珟圚無効なものは、別のハヌドりェア䞊で、たたは別のタスクで非垞に効果的であるこずが刀明する可胜性がありたす基瀎の

次の蚘事では、メモリアクセスの順序メモリの順序-メモリバリアメモリフェンス、メモリバリアに぀いお説明したす。参照[Cha05] Dean Chandler は.NETでの停共有を削枛、2005幎、Intel Corporation [Fra03] Keir Fraser





Practical Lock Freedom、2004; 技術報告曞は提出論文に基づいおいたす 9月、その埌ケンブリッゞ倧孊、キングスカレッゞに哲孊博士の孊䜍によっおK.Fraser 2003

[McKen05]トヌマス・ハヌトによるポヌルMcKenney、ゞョナサン・りォルポヌルのスケヌラブルな同期のための実甚的な懞念

マむケルによっお[Mic04] Maged 単䞀単語呜什を䜿甚したABA防止、IBM Research Report、2004

Source: https://habr.com/ru/post/J195948/


All Articles