Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.
Lockfree List
Lockfree List って? <ul><li>複数のスレッドから同時に挿入・検索・削除を行う事が可能な並行線形リストを Lockfree にしたもの </li></ul><ul><li>挿入・削除が立て込んでいてもロックを用いないので検索...
挿入処理 A B C D リストの繋ぎ替え処理が一瞬で片付くように工夫して、検索処理の邪魔をしない CompareAndSwap( 以下 CAS) でポインタを差し替える
挿入処理 A B C D リストの繋ぎ替え処理が一瞬で片付くように工夫して、検索処理の邪魔をしない CompareAndSwap( 以下 CAS) でポインタを差し替える CAS
挿入処理 A B C D リストの繋ぎ替え処理が一瞬で片付くように工夫して、検索処理の邪魔をしない CompareAndSwap( 以下 CAS) でポインタを差し替える 成功
挿入処理 A B C D CAS を使う事によって、同一の場所に同時に複数の挿入が発生しても CAS E CAS
挿入処理 A B C D 片方が必ず失敗する 失敗 E 成功
挿入処理 A B C D 失敗したらもう一度接続先を改めてやりなおす E 失敗したのでやりなおし
挿入処理 A B C D 失敗したらもう一度接続先を改めてやりなおす E CAS
挿入処理 A B C D これで直列化できる E 成功
削除処理 A B C 挿入処理と同様に、ポインタを CAS で繋ぎ変える 削除
削除処理 A B C 挿入処理と同様に、ポインタを CAS で繋ぎ変える CAS
削除処理 A C B こうして追い出した後に B を delete - CASのおかげで、複数のスレッドが一つのノードを取り合っても複数回deleteせずに済む delete
削除処理 A C こうして追い出した後に B を delete - CASのおかげで、複数のスレッドが一つのノードを取り合っても複数回deleteせずに済む
しかし問題が <ul><li>BとCを同時に削除しようとするとデータ構造が破壊される </li></ul>A B C D 削除 削除
しかし問題が <ul><li>BとCを同時に削除しようとするとデータ構造が破壊される </li></ul>A B C D CAS CAS
しかし問題が <ul><li>BとCを同時に削除しようとするとデータ構造が破壊される </li></ul><ul><ul><li>削除したはずのCに接続されてしまう </li></ul></ul>A B C D delete delete
しかし問題が <ul><li>BとCを同時に削除しようとするとデータ構造が破壊される </li></ul><ul><ul><li>削除したはずのCに接続されてしまう </li></ul></ul><ul><ul><li>こちらを状況1と呼ぶこと...
しかし問題が <ul><li>削除されるノードの次に挿入する際も </li></ul>A B C D E 削除 挿入
しかし問題が <ul><li>削除されるノードの次に挿入する際も </li></ul>A B C D E CAS CAS
しかし問題が <ul><li>削除されるノードの次に挿入する際も </li></ul><ul><ul><li>挿入されたはずの物が孤立してしまう </li></ul></ul>A B C D E delete
しかし問題が <ul><li>削除されるノードの次に挿入する際も </li></ul><ul><ul><li>挿入されたはずの物が孤立してしまう </li></ul></ul><ul><ul><li>こちらを状況2と呼ぶことにします </li>...
そこで削除を2段階操作とする <ul><li>ポインタに削除マークを取り付け、削除操作をマーキング・削除の2ステップに分割する </li></ul><ul><li>削除マークとポインタは一つのCASで同時に扱う事ができるとする </li></u...
そうなると? A B C D α :ここまでイタレーションし削除マーキング
そうなると? A B C D α :そして CAS による削除を試みる CAS
そうなると? A B C D α :成功したなら良し
そうなると? <ul><li>先ほどの状況 1 は </li></ul><ul><ul><ul><li>α ・ β の 2 スレッドで同時に削除するとして </li></ul></ul></ul>A B C D α :ここまでイタレーションし削...
そうなると? <ul><li>先ほどの状況 1 は </li></ul><ul><ul><ul><li>α ・ β の 2 スレッドで同時に削除するとして </li></ul></ul></ul>A B C D α : CAS を試みる β :...
そうなると? <ul><li>先ほどの状況 1 は </li></ul><ul><ul><ul><li>α ・ β の 2 スレッドで同時に削除するとして </li></ul></ul></ul>A B C D α : B のポインタがマーキン...
そうなると? <ul><li>先ほどの状況 1 は </li></ul><ul><ul><ul><li>α ・ β の 2 スレッドで同時に削除するとして </li></ul></ul></ul>A C D α :リストの先頭からイタレーション...
そうなると? <ul><li>先ほどの状況 1 は </li></ul><ul><ul><ul><li>α ・ β の 2 スレッドで同時に削除するとして </li></ul></ul></ul>A C D α :削除マークを発見
そうなると? <ul><li>先ほどの状況 1 は </li></ul><ul><ul><ul><li>α ・ β の 2 スレッドで同時に削除するとして </li></ul></ul></ul>A C D α : CAS を試みる
そうなると? <ul><li>先ほどの状況 1 は </li></ul><ul><ul><ul><li>α ・ β の 2 スレッドで同時に削除するとして </li></ul></ul></ul><ul><ul><ul><li>直列化できる <...
そうなると? <ul><li>先ほどの状況 1 は </li></ul><ul><ul><ul><li>α ・ β の 2 スレッドで同時に削除するとして </li></ul></ul></ul><ul><ul><ul><li>直列化できる <...
そうなると? <ul><li>先ほどの状況2は </li></ul>A B C D E 削除 挿入
そうなると? <ul><li>先ほどの状況2は </li></ul>A B C D E α :削除マーキング β : CAS を試みる
そうなると? <ul><li>先ほどの状況2は </li></ul>A B C D E α :削除マーキング β :マークのせいで CAS 失敗
そうなると? <ul><li>先ほどの状況2は </li></ul>A B C D E α : CAS を試みる
そうなると? <ul><li>先ほどの状況2は </li></ul>A B C D E α : CAS 成功 β :リストの頭から再びイタレート
そうなると? <ul><li>先ほどの状況2は </li></ul>A C D E β :リストの頭から再びイタレート
そうなると? <ul><li>先ほどの状況2は </li></ul>A C D E β : CAS を試みる
そうなると? <ul><li>先ほどの状況2は </li></ul><ul><ul><li>直列化できる </li></ul></ul>A C D E β : CAS 成功
ポイント <ul><li>リストをイタレートするときは、削除マークが付いていないことを常に確認する </li></ul><ul><ul><li>付いているならその場で削除させる </li></ul></ul><ul><ul><ul><li>これ...
問題点 <ul><li>イテレータがしょっちゅうリストの先頭に戻ってしまうので </li></ul><ul><ul><li>コストが高い。なのでイタレートを進める度にロックを繰り返す悲観的ロックリストや、書き換えを行う時だけロックを行い、ロック...
話題 <ul><li>このリストではABA問題には未対処 </li></ul><ul><ul><li>挿入・削除が運悪く重なって、望まない状況で CAS が成功してしまう場合がある </li></ul></ul><ul><li>対処方法は2種類...
ABA問題って? A B C D α :ここまでイタレーションし削除マーキング
ABA問題って? A B C D α :そのまましばらく休眠
ABA問題って? A B C D α :そのまましばらく休眠 β :別の用事でイタレーションしてくる
ABA問題って? A B C D α :そのまましばらく休眠 β :マークを確認したので削除
ABA問題って? A B C D α :そのまましばらく休眠 β :マークを確認したので削除
ABA問題って? A B C D α :そのまましばらく休眠 γ : B の後に新規ノード X を挿入する
ABA問題って? A B X D α :そのまましばらく休眠 γ :挿入時に運悪く α が参照中のノードを使いまわしてしまう
ABA問題って? A B X D α :やっと目覚める
ABA問題って? A B X D α : C の削除を再開する
ABA問題って? A B X D α : CAS を発行 CAS C が保存されていた時と同じポインタを指してしまっている
ABA問題って? A B X D α :アドレスが一致しているので CAS 成功 削除する気の無かった X が削除されてしまう
ABA問題って? <ul><li>ここに書いた状況以外にも、アドレスを使いまわす限り、意図しないアドレス一致の危険性は付いて回る </li></ul><ul><li>更新カウンタを付ければノードが使い回された後でもカウンタの値を見る事で不一致を...
ABA問題って? <ul><li>そもそも他のスレッドが参照している最中のものを削除して使いまわすから悪い </li></ul><ul><li>じゃあ削除しなければ良い。でもどうやって? </li></ul><ul><ul><ul><li>参照...
Nächste SlideShare
Wird geladen in …5
×

Lockfree list

110.694 Aufrufe

Veröffentlicht am

  • Login to see the comments

Lockfree list

  1. 1. Lockfree List
  2. 2. Lockfree List って? <ul><li>複数のスレッドから同時に挿入・検索・削除を行う事が可能な並行線形リストを Lockfree にしたもの </li></ul><ul><li>挿入・削除が立て込んでいてもロックを用いないので検索がロックされない </li></ul>
  3. 3. 挿入処理 A B C D リストの繋ぎ替え処理が一瞬で片付くように工夫して、検索処理の邪魔をしない CompareAndSwap( 以下 CAS) でポインタを差し替える
  4. 4. 挿入処理 A B C D リストの繋ぎ替え処理が一瞬で片付くように工夫して、検索処理の邪魔をしない CompareAndSwap( 以下 CAS) でポインタを差し替える CAS
  5. 5. 挿入処理 A B C D リストの繋ぎ替え処理が一瞬で片付くように工夫して、検索処理の邪魔をしない CompareAndSwap( 以下 CAS) でポインタを差し替える 成功
  6. 6. 挿入処理 A B C D CAS を使う事によって、同一の場所に同時に複数の挿入が発生しても CAS E CAS
  7. 7. 挿入処理 A B C D 片方が必ず失敗する 失敗 E 成功
  8. 8. 挿入処理 A B C D 失敗したらもう一度接続先を改めてやりなおす E 失敗したのでやりなおし
  9. 9. 挿入処理 A B C D 失敗したらもう一度接続先を改めてやりなおす E CAS
  10. 10. 挿入処理 A B C D これで直列化できる E 成功
  11. 11. 削除処理 A B C 挿入処理と同様に、ポインタを CAS で繋ぎ変える 削除
  12. 12. 削除処理 A B C 挿入処理と同様に、ポインタを CAS で繋ぎ変える CAS
  13. 13. 削除処理 A C B こうして追い出した後に B を delete - CASのおかげで、複数のスレッドが一つのノードを取り合っても複数回deleteせずに済む delete
  14. 14. 削除処理 A C こうして追い出した後に B を delete - CASのおかげで、複数のスレッドが一つのノードを取り合っても複数回deleteせずに済む
  15. 15. しかし問題が <ul><li>BとCを同時に削除しようとするとデータ構造が破壊される </li></ul>A B C D 削除 削除
  16. 16. しかし問題が <ul><li>BとCを同時に削除しようとするとデータ構造が破壊される </li></ul>A B C D CAS CAS
  17. 17. しかし問題が <ul><li>BとCを同時に削除しようとするとデータ構造が破壊される </li></ul><ul><ul><li>削除したはずのCに接続されてしまう </li></ul></ul>A B C D delete delete
  18. 18. しかし問題が <ul><li>BとCを同時に削除しようとするとデータ構造が破壊される </li></ul><ul><ul><li>削除したはずのCに接続されてしまう </li></ul></ul><ul><ul><li>こちらを状況1と呼ぶことにします </li></ul></ul>A D
  19. 19. しかし問題が <ul><li>削除されるノードの次に挿入する際も </li></ul>A B C D E 削除 挿入
  20. 20. しかし問題が <ul><li>削除されるノードの次に挿入する際も </li></ul>A B C D E CAS CAS
  21. 21. しかし問題が <ul><li>削除されるノードの次に挿入する際も </li></ul><ul><ul><li>挿入されたはずの物が孤立してしまう </li></ul></ul>A B C D E delete
  22. 22. しかし問題が <ul><li>削除されるノードの次に挿入する際も </li></ul><ul><ul><li>挿入されたはずの物が孤立してしまう </li></ul></ul><ul><ul><li>こちらを状況2と呼ぶことにします </li></ul></ul>A C D E
  23. 23. そこで削除を2段階操作とする <ul><li>ポインタに削除マークを取り付け、削除操作をマーキング・削除の2ステップに分割する </li></ul><ul><li>削除マークとポインタは一つのCASで同時に扱う事ができるとする </li></ul><ul><ul><li>動的に確保したオブジェクトは大体4byte程度でアラインされているのでポインタの下位bitがそのままフラグとして使える </li></ul></ul><ul><li>リストを辿るスレッドは、マークされたノードを発見したらそれを削除する </li></ul>
  24. 24. そうなると? A B C D α :ここまでイタレーションし削除マーキング
  25. 25. そうなると? A B C D α :そして CAS による削除を試みる CAS
  26. 26. そうなると? A B C D α :成功したなら良し
  27. 27. そうなると? <ul><li>先ほどの状況 1 は </li></ul><ul><ul><ul><li>α ・ β の 2 スレッドで同時に削除するとして </li></ul></ul></ul>A B C D α :ここまでイタレーションし削除マーキング β :ここまでイタレーションし削除マーキング
  28. 28. そうなると? <ul><li>先ほどの状況 1 は </li></ul><ul><ul><ul><li>α ・ β の 2 スレッドで同時に削除するとして </li></ul></ul></ul>A B C D α : CAS を試みる β : CAS を試みる
  29. 29. そうなると? <ul><li>先ほどの状況 1 は </li></ul><ul><ul><ul><li>α ・ β の 2 スレッドで同時に削除するとして </li></ul></ul></ul>A B C D α : B のポインタがマーキングされているので CAS に失敗する β : A のポインタは変わらないので CAS に成功する
  30. 30. そうなると? <ul><li>先ほどの状況 1 は </li></ul><ul><ul><ul><li>α ・ β の 2 スレッドで同時に削除するとして </li></ul></ul></ul>A C D α :リストの先頭からイタレーションし直す
  31. 31. そうなると? <ul><li>先ほどの状況 1 は </li></ul><ul><ul><ul><li>α ・ β の 2 スレッドで同時に削除するとして </li></ul></ul></ul>A C D α :削除マークを発見
  32. 32. そうなると? <ul><li>先ほどの状況 1 は </li></ul><ul><ul><ul><li>α ・ β の 2 スレッドで同時に削除するとして </li></ul></ul></ul>A C D α : CAS を試みる
  33. 33. そうなると? <ul><li>先ほどの状況 1 は </li></ul><ul><ul><ul><li>α ・ β の 2 スレッドで同時に削除するとして </li></ul></ul></ul><ul><ul><ul><li>直列化できる </li></ul></ul></ul>A C D α : CAS 成功
  34. 34. そうなると? <ul><li>先ほどの状況 1 は </li></ul><ul><ul><ul><li>α ・ β の 2 スレッドで同時に削除するとして </li></ul></ul></ul><ul><ul><ul><li>直列化できる </li></ul></ul></ul>A D
  35. 35. そうなると? <ul><li>先ほどの状況2は </li></ul>A B C D E 削除 挿入
  36. 36. そうなると? <ul><li>先ほどの状況2は </li></ul>A B C D E α :削除マーキング β : CAS を試みる
  37. 37. そうなると? <ul><li>先ほどの状況2は </li></ul>A B C D E α :削除マーキング β :マークのせいで CAS 失敗
  38. 38. そうなると? <ul><li>先ほどの状況2は </li></ul>A B C D E α : CAS を試みる
  39. 39. そうなると? <ul><li>先ほどの状況2は </li></ul>A B C D E α : CAS 成功 β :リストの頭から再びイタレート
  40. 40. そうなると? <ul><li>先ほどの状況2は </li></ul>A C D E β :リストの頭から再びイタレート
  41. 41. そうなると? <ul><li>先ほどの状況2は </li></ul>A C D E β : CAS を試みる
  42. 42. そうなると? <ul><li>先ほどの状況2は </li></ul><ul><ul><li>直列化できる </li></ul></ul>A C D E β : CAS 成功
  43. 43. ポイント <ul><li>リストをイタレートするときは、削除マークが付いていないことを常に確認する </li></ul><ul><ul><li>付いているならその場で削除させる </li></ul></ul><ul><ul><ul><li>これにより削除済みのオブジェクトに対して操作をしてしまう状況を防げる </li></ul></ul></ul><ul><ul><li>付いていない事を確認したはずの物にいつの間にか削除マークが付いていたならイタレートを頭からやり直す </li></ul></ul>
  44. 44. 問題点 <ul><li>イテレータがしょっちゅうリストの先頭に戻ってしまうので </li></ul><ul><ul><li>コストが高い。なのでイタレートを進める度にロックを繰り返す悲観的ロックリストや、書き換えを行う時だけロックを行い、ロックに失敗したらリストの先頭に戻る楽観的ロックリストなどを状況に応じて使い分ける </li></ul></ul><ul><ul><ul><li>読み出し頻度が多い程、ロック粒度を細かくするほうが良い </li></ul></ul></ul><ul><ul><li>std::list<hoge>::iterator it; のような形として個々のスレッドにイテレータを持たせるのは無理 </li></ul></ul><ul><ul><ul><ul><li>そもそも STL の list::iterator も並列利用は無保証 </li></ul></ul></ul></ul><ul><ul><ul><ul><li>std::set のように挿入・検索・削除の利用のみ </li></ul></ul></ul></ul>
  45. 45. 話題 <ul><li>このリストではABA問題には未対処 </li></ul><ul><ul><li>挿入・削除が運悪く重なって、望まない状況で CAS が成功してしまう場合がある </li></ul></ul><ul><li>対処方法は2種類ある </li></ul><ul><ul><li>運悪く同じアドレスに CAS することになっても CAS が成功しないよう、ポインタに更新スタンプを付ける </li></ul></ul><ul><ul><ul><li>スタンプが運悪く一周してしまうとやはり ABA 問題 </li></ul></ul></ul><ul><ul><li>参照している最中のオブジェクトは削除しない事にする </li></ul></ul><ul><ul><ul><li>参照カウンタ? ->  atomic カウンタ重いです… </li></ul></ul></ul><ul><ul><ul><li>ガベージコレクタ? -> マルチスレッド対応の GC が必要 </li></ul></ul></ul><ul><ul><ul><li>ハザードポインタ -> 当店お勧め </li></ul></ul></ul>
  46. 46. ABA問題って? A B C D α :ここまでイタレーションし削除マーキング
  47. 47. ABA問題って? A B C D α :そのまましばらく休眠
  48. 48. ABA問題って? A B C D α :そのまましばらく休眠 β :別の用事でイタレーションしてくる
  49. 49. ABA問題って? A B C D α :そのまましばらく休眠 β :マークを確認したので削除
  50. 50. ABA問題って? A B C D α :そのまましばらく休眠 β :マークを確認したので削除
  51. 51. ABA問題って? A B C D α :そのまましばらく休眠 γ : B の後に新規ノード X を挿入する
  52. 52. ABA問題って? A B X D α :そのまましばらく休眠 γ :挿入時に運悪く α が参照中のノードを使いまわしてしまう
  53. 53. ABA問題って? A B X D α :やっと目覚める
  54. 54. ABA問題って? A B X D α : C の削除を再開する
  55. 55. ABA問題って? A B X D α : CAS を発行 CAS C が保存されていた時と同じポインタを指してしまっている
  56. 56. ABA問題って? A B X D α :アドレスが一致しているので CAS 成功 削除する気の無かった X が削除されてしまう
  57. 57. ABA問題って? <ul><li>ここに書いた状況以外にも、アドレスを使いまわす限り、意図しないアドレス一致の危険性は付いて回る </li></ul><ul><li>更新カウンタを付ければノードが使い回された後でもカウンタの値を見る事で不一致を検出できるため問題を回避できるが、一度に CAS しなくてはならないビット数が増えるため、 DCAS 命令や STM が必要になる </li></ul><ul><ul><li>更新カウンタに割くビット数をケチるとカウンタが一巡して一致する危険性がある </li></ul></ul>
  58. 58. ABA問題って? <ul><li>そもそも他のスレッドが参照している最中のものを削除して使いまわすから悪い </li></ul><ul><li>じゃあ削除しなければ良い。でもどうやって? </li></ul><ul><ul><ul><li>参照カウンタ->カウンタをatomicに操作する必要がある上、ノードごとにカウンタが付くためリストが肥大化 </li></ul></ul></ul><ul><ul><ul><li>ガベージコレクタ->GC中に全スレッドを止めるしか安全な方法が無い </li></ul></ul></ul><ul><li>そこでハザードポインタです(次回へ </li></ul>

×