Michael &Scott 无锁队列 C++ 实现
最近在研究无锁算法, 参照Michael and Scott的伪码,实现了个c++版本。
参考 http://www.cs.rochester.edu/research/synchronization/pseudocode/queues.html
伪代码是:
structure pointer_t {ptr: pointer to node_t, count: unsigned integer}
structure node_t {value: data type, next: pointer_t}
structure queue_t {Head: pointer_t, Tail: pointer_t}
initialize(Q: pointer to queue_t)
node = new_node() // Allocate a free node
node->next.ptr = NULL // Make it the only node in the linked list
Q->Head.ptr = Q->Tail.ptr = node // Both Head and Tail point to it
enqueue(Q: pointer to queue_t, value: data type)
E1: node = new_node() // Allocate a new node from the free list
E2: node->value = value // Copy enqueued value into node
E3: node->next.ptr = NULL // Set next pointer of node to NULL
E4: loop // Keep trying until Enqueue is done
E5: tail = Q->Tail // Read Tail.ptr and Tail.count together
E6: next = tail.ptr->next // Read next ptr and count fields together
E7: if tail == Q->Tail // Are tail and next consistent?
// Was Tail pointing to the last node?
E8: if next.ptr == NULL
// Try to link node at the end of the linked list
E9: if CAS(&tail.ptr->next, next, <node, next.count+1>)
E10: break // Enqueue is done. Exit loop
E11: endif
E12: else // Tail was not pointing to the last node
// Try to swing Tail to the next node
E13: CAS(&Q->Tail, tail, <next.ptr, tail.count+1>)
E14: endif
E15: endif
E16: endloop
// Enqueue is done. Try to swing Tail to the inserted node
E17: CAS(&Q->Tail, tail, <node, tail.count+1>)
dequeue(Q: pointer to queue_t, pvalue: pointer to data type): boolean
D1: loop // Keep trying until Dequeue is done
D2: head = Q->Head // Read Head
D3: tail = Q->Tail // Read Tail
D4: next = head.ptr->next // Read Head.ptr->next
D5: if head == Q->Head // Are head, tail, and next consistent?
D6: if head.ptr == tail.ptr // Is queue empty or Tail falling behind?
D7: if next.ptr == NULL // Is queue empty?
D8: return FALSE // Queue is empty, couldn't dequeue
D9: endif
// Tail is falling behind. Try to advance it
D10: CAS(&Q->Tail, tail, <next.ptr, tail.count+1>)
D11: else // No need to deal with Tail
// Read value before CAS
// Otherwise, another dequeue might free the next node
D12: *pvalue = next.ptr->value
// Try to swing Head to the next node
D13: if CAS(&Q->Head, head, <next.ptr, head.count+1>)
D14: break // Dequeue is done. Exit loop
D15: endif
D16: endif
D17: endif
D18: endloop
D19: free(head.ptr) // It is safe now to free the old node
D20: return TRUE // Queue was not empty, dequeue succeeded
structure node_t {value: data type, next: pointer_t}
structure queue_t {Head: pointer_t, Tail: pointer_t}
initialize(Q: pointer to queue_t)
node = new_node() // Allocate a free node
node->next.ptr = NULL // Make it the only node in the linked list
Q->Head.ptr = Q->Tail.ptr = node // Both Head and Tail point to it
enqueue(Q: pointer to queue_t, value: data type)
E1: node = new_node() // Allocate a new node from the free list
E2: node->value = value // Copy enqueued value into node
E3: node->next.ptr = NULL // Set next pointer of node to NULL
E4: loop // Keep trying until Enqueue is done
E5: tail = Q->Tail // Read Tail.ptr and Tail.count together
E6: next = tail.ptr->next // Read next ptr and count fields together
E7: if tail == Q->Tail // Are tail and next consistent?
// Was Tail pointing to the last node?
E8: if next.ptr == NULL
// Try to link node at the end of the linked list
E9: if CAS(&tail.ptr->next, next, <node, next.count+1>)
E10: break // Enqueue is done. Exit loop
E11: endif
E12: else // Tail was not pointing to the last node
// Try to swing Tail to the next node
E13: CAS(&Q->Tail, tail, <next.ptr, tail.count+1>)
E14: endif
E15: endif
E16: endloop
// Enqueue is done. Try to swing Tail to the inserted node
E17: CAS(&Q->Tail, tail, <node, tail.count+1>)
dequeue(Q: pointer to queue_t, pvalue: pointer to data type): boolean
D1: loop // Keep trying until Dequeue is done
D2: head = Q->Head // Read Head
D3: tail = Q->Tail // Read Tail
D4: next = head.ptr->next // Read Head.ptr->next
D5: if head == Q->Head // Are head, tail, and next consistent?
D6: if head.ptr == tail.ptr // Is queue empty or Tail falling behind?
D7: if next.ptr == NULL // Is queue empty?
D8: return FALSE // Queue is empty, couldn't dequeue
D9: endif
// Tail is falling behind. Try to advance it
D10: CAS(&Q->Tail, tail, <next.ptr, tail.count+1>)
D11: else // No need to deal with Tail
// Read value before CAS
// Otherwise, another dequeue might free the next node
D12: *pvalue = next.ptr->value
// Try to swing Head to the next node
D13: if CAS(&Q->Head, head, <next.ptr, head.count+1>)
D14: break // Dequeue is done. Exit loop
D15: endif
D16: endif
D17: endif
D18: endloop
D19: free(head.ptr) // It is safe now to free the old node
D20: return TRUE // Queue was not empty, dequeue succeeded
我的 C++实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | #ifndef __FIFO_LOCK_FREE_H__ #define __FIFO_LOCK_FREE_H__ #include <stddef.h> #include <stdint.h> #include <stdlib.h> #include <malloc.h> namespace conet { class fifo_lockfree_t { public : typedef void * data_type; struct node_t; struct pointer_t { node_t *ptr; uint64_t tag; pointer_t() { ptr = NULL; tag = 0; } pointer_t(node_t *a_ptr, uint64_t a_tag) { ptr = a_ptr; tag=a_tag; } pointer_t(pointer_t const & a) { ptr = a.ptr; tag = a.tag; } } __attribute__ ((packed, aligned (16))) ; struct node_t { volatile pointer_t next; void * value; node_t() { value = NULL; // dummy_val next.ptr = NULL; next.tag = 0; } void reinit( void *val = NULL) { next.ptr = NULL; next.tag = 0; value = val; } }; static inline bool CAS2(pointer_t volatile *addr, pointer_t &old_value, pointer_t &new_value) { bool ret; __asm__ __volatile__( "lock cmpxchg16b %1;\n" "sete %0;\n" : "=m" (ret), "+m" (*( volatile pointer_t *) (addr)) : "a" (old_value.ptr), "d" (old_value.tag), "b" (new_value.ptr), "c" (new_value.tag)); return ret; } public : //var members volatile pointer_t tail_; volatile pointer_t head_; public : fifo_lockfree_t() { } static node_t * alloc_node() { node_t *nd = (node_t *)memalign(16, sizeof (node_t)); nd->reinit(NULL); return nd; } static void free_node(node_t *nd) { free (nd); } void init() { node_t *nd = alloc_node(); head_.ptr = nd; head_.tag = 0; tail_.ptr = nd; tail_.tag = 0; } void push(node_t *nd, void * val) { pointer_t tail, next; nd->value = val; nd->next.ptr = NULL; while (1) { tail.ptr = this ->tail_.ptr; tail.tag = this ->tail_.tag; next.ptr = tail.ptr->next.ptr; next.tag = tail.ptr->next.tag; if ((tail.ptr == this ->tail_.ptr) && (tail.tag == this ->tail_.tag)) { if (next.ptr == NULL) { pointer_t new_pt; new_pt.ptr = (node_t *)nd; new_pt.tag = next.tag+1; nd->next.tag = new_pt.tag; if (CAS2(&( this ->tail_.ptr->next), next, new_pt)){ break ; // Enqueue done! } } else { pointer_t new_pt(next.ptr, tail.tag+1); nd->next.tag = new_pt.tag; CAS2(&( this ->tail_), tail, new_pt); } } } pointer_t new_pt(nd, tail.tag+1); CAS2(&( this ->tail_), tail, new_pt); } node_t * pop() { pointer_t tail, head, next; void * value = NULL; while (1) { head.ptr = this ->head_.ptr; head.tag = this ->head_.tag; tail.ptr = this ->tail_.ptr; tail.tag = this ->tail_.tag; next.ptr = (head.ptr)->next.ptr; next.tag = (head.ptr)->next.tag; if ( (head.ptr == this ->head_.ptr) && (head.tag == this ->head_.tag) ) { if (head.ptr == tail.ptr){ if (next.ptr == NULL){ return NULL; } pointer_t new_pt(next.ptr, tail.tag+1); CAS2(&( this ->tail_), tail, new_pt); } else { value = next.ptr->value; pointer_t new_pt(next.ptr, head.tag+1); if (CAS2(&( this ->head_), head, new_pt)){ break ; } } } } node_t *nd = head.ptr; nd->value = value; return nd; } }; } #endif |
gcc 4.1.2 编译, Linux下 经过框架测试没有问题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现