再帰読み書き
超スマートポインタの話の続き。
今回の条件をより正確に書くと
- 循環検出と循環検出は排他する。
- ポインタaの参照上げ下げとaの参照上げ下げは排他する。
- 異なるポインタa, bについて、aの参照上げ下げとbの参照上げ下げは排他しない。
- スレッドXが循環検出中の場合、Xが行うポインタaの参照上げ下げは許可する。
- スレッドXが循環検出中の場合、Xと異なるスレッドYが行うポインタaの参照上げ下げは許可しない。
というのが正しいようだ。各ポインタについては単なるmutexで良い。循環検出を守るには単なるread-write lockではダメで、recursive read-write lockとでも呼ぶべきものが必要だ。
しかし、pthreadにはそのようなものはない。他のライブラリでも見付からなかった。そのような需要自体が少ないのかも知れない。
それでは普通のread-write lockとrecursive mutexを組み合わせてrecursive read-write lockとして振舞うようにすれば良さそうだ。
rwlock_t rw; rec_mutex_t m; void write() { wrlock(&rw); lock(&m); //排他でのwrite作業 unlock(&m); unlock(&rw); } void read() { const int rdlockerr = tryrdlock(&rw); if (rdlockerr) { lock(&m); } //排他でのread作業 if (rdlockerr) { unlock(&m); } else { unlock(&rw); } }
フラグ判定を二箇所に書いているのはちょっと不格好かも。wrlock中のread作業は一つずつしか処理出来ないようになっているが、wrlockを通るスレッドが一つであるうちは問題ない(もちろん拡張性は低い)。
これで参照カウントがマルチスレッド対応になる。循環検出の間はほぼ全スレッドが停止してしまうのが欠点か。それでもMark&Sweepよりは停止時間が短いはず。
http://www.research.ibm.com/people/d/dfb/papers/Bacon01Concurrent.pdfの論文のConcurrent版を実装すれば停止時間は減るかもしれない。でも、そのまま書いたら循環検出してくれなかったのだよな。scan()中でscan_black()を呼ぶ条件がおかしい気がする。