参考论文 Implementing Lock-Free Queues
ConQueue实现了无锁并发循环队列,采用数组存储队列的数据。
con_queue.hpp
#ifndef CON_QUEUE_H_
#define CON_QUEUE_H_
#include <atomic>
#include <vector>
using namespace std;
namespace eventsock{
template<typename T>
class ConQueue{
private:
T* m_data; //存储队列节点的数组
int m_data_len; //数组m_data的长度
int m_tail;
int m_head;
atomic_uint m_size;
public:
ConQueue(T* data, int data_len): m_tail(0), m_size(0){
m_data = data;
m_data_len = data_len;
// m_head表示第一个元素
m_head = 0;
// m_tail标记队列尾部,不包含元素
m_tail = 0;
}
bool push(T value){
int old_tail, new_tail;
while(true){
old_tail = m_tail;
new_tail = (old_tail + 1) % m_data_len;
//队列已满
if(new_tail == m_head) return false;
if(__sync_bool_compare_and_swap(&m_tail, old_tail, new_tail)){
m_data[old_tail] = value;
m_size++;
break;
}
}
return true;
}
bool pop(){
int old_head, new_head;
while(true){
old_head = m_head;
if(old_head == m_tail) break;
new_head = (old_head + 1) % m_data_len;
if(__sync_bool_compare_and_swap(&m_head, old_head, new_head)){
m_size--;
return true;
}
}
return false;
}
size_t size(){
return m_size;
}
bool empty(){
return m_head == m_tail;
}
void output(){
int head = m_head, tail = m_tail;
int pos = head;
cout << "[";
while(pos != tail){
if(pos != head){
cout << ",";
}
cout << m_data[pos];
pos = (pos + 1) % m_data_len;
}
cout << "]" << endl;
}
vector<T> to_vector(){
vector<T> vec;
int head = m_head, tail = m_tail;
int pos = head;
while(pos != tail){
vec.push_back(m_data[pos]);
pos = (pos + 1) % m_data_len;
}
return vec;
}
};
}
#endif
测试例程
#include <iostream>
#include "con_queue.hpp"
#include <vector>
#include <thread>
#include <atomic>
#include <algorithm>
#include <queue>
const int per_time = 500000;
const int NUM = 100000;
int que[NUM];
eventsock::ConQueue<int> con_queue(que, NUM);
void test_queue_push(int k){
for(int i = k * per_time; i < k * per_time + per_time; i++){
while(true){
if(con_queue.push(i)) break;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
};
}
}
void test_queue_pop(int k){
for(int i = k * per_time; i < k * per_time + per_time; i++){
while(true){
if(con_queue.pop()) break;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
};
}
}
void test_con_queue(){
vector<thread> ths;
for(int i = 0; i < 10; i++){
ths.push_back(thread(test_queue_push, i));
}
for(int i = 0; i < 10; i++){
ths.push_back(thread(test_queue_pop, i));
}
for(int i = 0; i < ths.size(); i++){
ths[i].join();
}
int num = con_queue.size();
con_queue.output();
if(num == 0){
printf("ConQueue success\n");
}else{
printf("EventConnection fail num=%d\n", num);
}
}
int main(int argc, char* argv[])
{
test_con_queue();
return 0;
}