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++实现:
#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下 经过框架测试没有问题。

浙公网安备 33010602011771号