C++無鎖程式設計資料,無鎖佇列等
1. Lamport's Lock-Free Ring Buffer
[Lamport, Comm. of ACM, 1977]
也就常說的單生產者-單消費者 的ringbuffer, 限制就是隻能一個讀執行緒(消費者),一個寫程序(生產者)。
好像有人改進了一下設計, 參加文章 “Cache優化的併發無鎖佇列” http://www.docin.com/p-30332640.html ,這論文裡面 “Fastforward for efficient pipeline parallelism: A Cache-Optimized Concurrent Lock-Free Queue ” 裡面有說
. Lamport’s queue implementation
=================================
1 enqueue_nonblock(data) {
2 if (NEXT(head) == tail) { 同時訪問 head和tail
3 return EWOULDBLOCK;
4 }
5 buffer[head] = data;
6 head = NEXT(head);
7 return 0;
8 }
1 dequeue_nonblock(data) {
2
3 if (head == tail) { 同時訪問 head和tail
4 return EWOULDBLOCK;
5 }
6 data = buffer[tail];
7 tail = NEXT(tail);
8 return 0;
9 }
-----------------------------
FastForward queue implementation
==============================
1 enqueue_nonblock(data) {
2 if (NULL != buffer[head]) { 通過避免同時在 讀寫執行緒中訪問head和tail兩個變數來避免cache抖動的的更好的效能
3 return EWOULDBLOCK;
4 }
5 buffer[head] = data;
6 head = NEXT(head);
7 return 0;
8 }
1 dequeue_nonblock(data) {
2 data = buffer[tail]; 只訪問tail
3 if (NULL == data) {
4 return EWOULDBLOCK;
5 }
6 buffer[tail] = NULL;
7 tail = NEXT(tail);
8 return 0;
9
2, Michael &Scott 無鎖佇列
支援多個讀執行緒(消費者)和多個寫程序(生產者)同時工作
“Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms”
這裡http://www.cs.rochester.edu/research/synchronization/pseudocode/queues.html 有偽碼,
有人按照這個用C++實現了,http://www.cnblogs.com/napoleon_liu/archive/2010/08/07/1794566.html
其實就是在修改連結串列指標時,利用intel的CAS(compare and swap交換和賦值)原子指令來做具體的修改賦值。我記得linux核心程式碼看到比較多的是xchg系列,上面的那個blog利用的lock字首的“"lock cmpxchg16b”指令,應該一樣的道理。一般都是搞個while迴圈直到修改成功。
另有呂慧偉 縮寫的“無鎖程式設計簡介An Intro to Lock-free Programming” http://www.tektalk.org/wp-content/uploads/2011/07/lock-free-intro1.pdf 給了一個簡單的原始碼
void enQ(request, queue)
{
do{
local_head = queue->head;
request->next = queue->head;
val = cmpxchg(&queue->head,
local_head, request);
}while(val != local_head)
}
類似的可以利用CAS實現無鎖堆疊 程式碼同樣來自呂慧偉的文章
struct elem {
elem *link
any data;
}
elem *qhead;
---------------
Push (elem *x)
do
old = qhead;
x->link = old;
new = x;
cc = CAS(qhead, old, new);
until (cc == old;
--------------
Pop ()
do
old = qhead;
new = old->link;
cc = CAS(qhead, old, new);
until (cc == old;)
return old
-----------------
另外需要的注意點是,文章提到如果不同的執行緒裡面使用一個共享的元素來做插入和刪除操作時是有非常嚴重的“ABA問題”的,會導致元素的丟失, CAS指令不能分辨這個元素是不是在本執行緒被中斷之後,又已經被另外的執行緒取出(已經被消費了)再重新作為新的元素又被插入的情況,這是CAS就會導致多刪了一個元素。這時就要引入個操作的序列號區來進行區分,解決問題。去看一下原文吧。
“錢立兵 陳波 晏濤 徐雲 孟金濤 劉濤” 等人寫的“多執行緒併發訪問無鎖佇列的演算法研究” http://www.siat.ac.cn/xscbw/xsqk/200906/W020091127490148897561.pdf
提到一個 Edya Ladan-Mozes和 Nir Shavit 的optimistic演算法演算法,所示上面的 Michael &Scott方法的改進,可以通過 更少的CAS指令來完成操作。 (Edya Ladan-Mozes and Nir Shavit.An optimistic approach to
lock-free FIFO queues. Department of Computer Science, TelAviv University, Israel. Distributed Computing, 30 November 2007)
可以去找來看一下。
3. 上面的提到的ABA 問題好像是無鎖程式設計裡面很主要的一個問題啊。
根據 cds 庫的資料,有下面三類解決辦法,可以去找論文來看一下。
M.Michael's Hazard Pointer
--------------------
[2002] Maged M.Michael "Safe memory reclamation for dynamic lock-freeobjects using atomic reads and writes"
[2003] Maged M.Michael "Hazard Pointers: Safe memory reclamation for lock-free objects"
[2004] Andrei Alexandrescy, Maged Michael "Lock-free Data Structures with Hazard Pointers"
--------------------
Gidenstam's memory reclamation schema based on Hazard Pointer and reference counting
[2006] A.Gidenstam "Algorithms for synchronization and consistency in concurrent system services", Chapter 5 "Lock-Free Memory Reclamation" Thesis for the degree of Doctor of Philosophy
[2005] Anders Gidenstam, Marina Papatriantafilou and Philippas Tsigas "Allocating memory in a lock-free manner", Proceedings of the 13th Annual European Symposium on Algorithms (ESA 2005), Lecture Notes in Computer Science Vol. 3669, pages 229 – 242, Springer-Verlag, 2005
--------------------
M.Herlihy and M.Moir's Pass The Buck algorithm
[2002] M. Herlihy, V. Luchangco, and M. Moir. The repeat offender problem: A mechanism for supporting dynamic-sized lockfree data structures. Technical Report TR-2002-112, Sun Microsystems Laboratories, 2002
[2002] M. Herlihy, V. Luchangco, P. Martin, and M. Moir. Dynamic-sized Lockfree Data Structures. Technical Report TR-2002-110, Sun Microsystems Laboratories, 2002
[2005] M. Herlihy, V. Luchangco, P. Martin, and M. Moir. Nonblocking Memory Management Support for Dynamic_Sized Data Structures. ACM Transactions on Computer Systems, Vol.23, No.2, May 2005
----------------------
4. libcds庫提到的其他無鎖結構stack 和Split-Ordered List 等相關的論文
Treiber's stack algorithm.
R. K. Treiber. Systems programming: Coping with
parallelism. Technical Report RJ 5118, IBM Almaden
Research Center, April 1986
Danny Hendler 等人的Treiber stack的改進
A Scalable Lock-free Stack Algorithm
http://www.cs.tau.ac.il/~shanir/nir-pubs-web/Papers/Lock_Free.pdf
---------------------
Michael's hash map.
Source:
[2002] Maged Michael "High performance dynamic lock-free hash tables and list-based sets"
-----------------------
Hash table implementation based on split-ordered list algorithm discovered by Ori Shalev and Nir Shavit, see
[2003] Ori Shalev, Nir Shavit "Split-Ordered Lists - Lock-free Resizable Hash Tables"
[2008] Nir Shavit "The Art of Multiprocessor Programming"
5. C++無鎖資料結構支援庫 CDS: Concurrent Data Structures library
實現了很多無鎖的stack(棧),queue(佇列),hashmap ,list 等容器
前面說到的兩個queue都有實現
1)Michael & Scott lock-free queue
2)Optimistic queue
3)cds::container::MichaelHashMap cds::container::MichaelHashSet
Intel® Threading Building Blocks 庫(http://threadingbuildingblocks.org/)裡面也有很多並行的 queue map等容器,但沒說是不是無鎖設計的。
最初是從 http://hi.baidu.com/ah__fu/blog/item/3081cd341a6364205ab5f5a4.html 看到這個庫的介紹的。
6, The Art of Multiprocessor Programming.pdf
一書對 無鎖 queue stack 和skiplist ABA問題都有所介紹,可以去看一下,寫的不錯的書。
7. 好像大家都期待一種叫做“Transac1tiona8l Memory”的最終解決方案來來徹底解決記憶體同步、無鎖程式設計之類問題,不過好像沒有到可用的程度吧。