一次无锁循环队列的编写回顾

来源:互联网 发布:网络社会组织 编辑:程序博客网 时间:2024/05/19 13:57

  今天写了一个无锁队列,代码比较短,但是调试时间比较久,主要的几个问题是:
  

  1. 函数用法不清楚(CAS)
  2. 函数起名不准确,导致用错
  3. 算法不熟练,导致调试时发现算法的偏移又问题
    代码如下:
#ifndef LYY_LIB_LOCK_FREE_QUEUE_H#define LYY_LIB_LOCK_FREE_QUEUE_H#include <vector>#include <cstdint>using std::vector;namespace lyy {    #define CAS __sync_bool_compare_and_swap    enum NodeStatus {        STATUS_IDLE,        STATUS_ADDING,        STATUS_READY,        STATUS_REMOVING,    };    struct Node {        void *ptr;        int status;    };    class Queue {        public:            Queue() : _max_queue_size(100) {            }            Queue(int max_queue_size) : _max_queue_size(max_queue_size) {            }            virtual void * get() = 0;            virtual void put(void* t) = 0;        protected:            int _max_queue_size;    };    class LockFreeQueue : public Queue {        public:            LockFreeQueue() : _head_tail(0) {                _data.resize(_max_queue_size);            }            LockFreeQueue(int max_queue_size) : Queue(max_queue_size), _head_tail(0) {                _data.resize(_max_queue_size);            }            void * get();            void put(void* t);            int empty();            int full();        private:            bool add_tail(uint64_t &);            bool add_head(uint64_t &);        private:            vector<Node> _data;            uint64_t _head_tail;    };}#endif
cpp:
#include "queue.h"#include <pthread.h>#include <unistd.h>namespace lyy {bool LockFreeQueue::add_tail(uint64_t & new_head_tail) {    uint32_t cur_size = 0;    uint32_t tail = _head_tail & 0xFFFFFFFF;    uint32_t head = (uint32_t)(_head_tail >> 32);    if (tail >= head) {        cur_size = tail -head;    } else {        cur_size = tail + _max_queue_size - head;    }    if (cur_size == _max_queue_size - 1) {        return false;    }    tail = (tail + 1) % (_max_queue_size);    new_head_tail = (((uint64_t)head)<<32) | tail;    return true;}bool LockFreeQueue::add_head(uint64_t & new_head_tail) {    uint32_t cur_size = 0;    uint32_t tail = _head_tail & 0xFFFFFFFF;    uint32_t head = (uint32_t)(_head_tail >> 32);    if (tail >= head) {        cur_size = tail -head;    } else {        cur_size = tail + _max_queue_size - head;    }    if (cur_size == 0) {        return false;    }    head = (head + 1) % _max_queue_size;    new_head_tail = (((uint64_t)head)<<32) | tail;    return true;}void *LockFreeQueue::get() {    uint64_t new_head_tail = 0;    uint64_t old_head_tail = _head_tail;    int retry = 3;    bool suc = true;    do {        do {            old_head_tail = _head_tail;            if ((suc = add_head(new_head_tail))) {            } else {                if (retry--) {                    usleep(5);                } else {                    pthread_yield();                }            }        } while (!suc);        retry = 3;    } while (!CAS(&_head_tail, old_head_tail, new_head_tail));    uint32_t head = ((new_head_tail >> 32)  + _max_queue_size - 1) % _max_queue_size;    Node * node = &_data[head];             do {    } while (!CAS(&node->status, STATUS_READY,STATUS_REMOVING));    void *ptr= node->ptr;    node->ptr = NULL;    node->status = STATUS_IDLE;    return ptr;}void LockFreeQueue::put(void *ptr) {    uint64_t new_head_tail = 0;    uint64_t old_head_tail = _head_tail;    int retry = 3;    bool suc = false;    do {        do {            old_head_tail = _head_tail;            if (suc = add_tail(new_head_tail)) {            } else {                if (retry--) {                    usleep(5);                } else {                    pthread_yield();                }            }        } while (!suc);        retry = 3;    } while (!CAS(&_head_tail, old_head_tail, new_head_tail));    uint32_t tail = new_head_tail & 0xFFFFFFFF;    Node * node = &_data[(tail + _max_queue_size - 1) % _max_queue_size];             do {    } while (!CAS(&node->status, STATUS_IDLE, STATUS_ADDING));    node->ptr = ptr;    node->status = STATUS_READY;}}

  测试代码:
  

#include "queue.h"#include <iostream>#include <sstream>#include <cstdlib>#include <cstdio>struct Context {    lyy::LockFreeQueue *q;};struct Data {    pthread_t tid;    int value;    void print() {        std::ostringstream oss;        oss << "tid:" << tid << " value:" << value << std::endl;        printf("%s",oss.str().c_str());    }};void* put(void *ptr) {    Context *context = (Context *)ptr;    pthread_t tid = pthread_self();    std::ostringstream oss;    oss << "---------put start[tid:" <<tid << "]-------------\n";    printf("%s", oss.str().c_str());    for (int i = 0; i < 5; ++ i) {        Data *data = (Data*)malloc(sizeof(Data));        data->tid = tid;        data->value = i;        context->q->put(data);    }}void *get(void *ptr) {    Context *context = (Context *)ptr;    pthread_t tid = pthread_self();    std::ostringstream oss;    oss << "---------get start[tid:" <<tid << "]-------------\n";    printf("%s", oss.str().c_str());    for (int i = 0; i < 5; ++i) {       Data *data = (Data*) context->q->get();       if (data != NULL) {            data->print();       }    }}int main() {    lyy::LockFreeQueue queue;    Context context;    context.q = &queue;    int get_thread_num = 100;    int put_thread_num = 100;    std::vector<pthread_t> get_pthread_ts(get_thread_num, 0);    std::vector<pthread_t> put_pthread_ts(put_thread_num, 0);    for (int i = 0; i < get_thread_num; ++i) {        pthread_create(&get_pthread_ts[i], NULL, get, &context);        pthread_create(&put_pthread_ts[i], NULL, put, &context);    }    for (int i = 0; i < get_thread_num; ++i) {        pthread_join(get_pthread_ts[i], NULL);        pthread_join(put_pthread_ts[i], NULL);    }}

  add_tail&add_head 的名字问题:add_head和add_tail名字表达不准确,add_head应该叫remove_head
  CAS的比较结果没有注意函数结果,导致出错

原创粉丝点击