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

 

我的 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下 经过框架测试没有问题。

posted @ 2010-08-07 09:53  napoleon_liu  阅读(7640)  评论(13编辑  收藏  举报