一次无锁循环队列的编写回顾
来源:互联网 发布:网络社会组织 编辑:程序博客网 时间:2024/05/19 13:57
今天写了一个无锁队列,代码比较短,但是调试时间比较久,主要的几个问题是:
- 函数用法不清楚(CAS)
- 函数起名不准确,导致用错
- 算法不熟练,导致调试时发现算法的偏移又问题
代码如下:
#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的比较结果没有注意函数结果,导致出错
阅读全文
0 0
- 一次无锁循环队列的编写回顾
- 无锁队列的实现-循环数组
- [C]无锁循环队列
- 用c++编写的数据结构循环队列
- C#数据结构回顾之循环队列
- 无锁队列的实现
- 无锁队列的实现
- 无锁队列的实现
- 无锁队列的实现
- 无锁队列的实现
- 无锁队列的实现
- 无锁队列的实现
- 无锁队列的实现
- 无锁队列的实现
- 无锁队列的实现
- 无锁队列的实现
- 无锁队列的实现
- 无锁队列的实现
- 深度强化学习(Deep Reinforcement Learning)入门:RL base & DQN-DDPG-A3C introduction
- activemq group分组
- 关于windows下QT5.X编译mysql后找不到生成文件的问题
- Python数据分析基础(三)——pandas
- codeforces544E
- 一次无锁循环队列的编写回顾
- 【mysql】查询性能优化
- 补补嵌入式系统基础知识
- 排序算法
- jass 重置英雄
- Python数据分析基础(四)——数据文件处理
- 你要知道的游戏开发新手入门指南
- springmvc 整合 swagger2
- Generate Parentheses