/*************************************************************************
> File Name: DoubleLockedQueue.h
> Author: wangzhicheng
> Mail: 2363702560@qq.com
> Created Time: 2017-01-02
> Statement: double locked concurrent queue
************************************************************************/
#ifndef DOUBLE_LOCKED_QUEUE_H
#define DOUBLE_LOCKED_QUEUE_H
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <atomic>
#include <mutex>
namespace doublelockedqueue
{
using namespace std;
static const int MAXCAP = 1000000000;
/*
* the Node of queue
* */
template<class DataType>
class QueueNode
{
public:
DataType m_Data; // pointer to the data which needed to be put in the queue
QueueNode<DataType>*m_pNext; // the next pointer
QueueNode()
{
m_pNext = NULL;
}
QueueNode(const DataType &data, QueueNode *next = NULL)
{
m_Data = data;
m_pNext = next;
}
~QueueNode()
{
m_pNext = NULL;
}
};
/*
* double locked queue
* */
template<class DataType>
class DoubleLockedQueue
{
private:
mutex m_Head_Lock; // for dequeue
mutex m_Tail_Lock; // for enqueue
QueueNode<DataType> *m_pHead;
QueueNode<DataType> *m_pTail;
atomic<int>m_nNum; // 用于计数
int m_nMaxLen; // 队列最大长度
public:
DoubleLockedQueue();
/*
* @brief 初始化队列容量和头结点
* */
void Init(int max);
/*
* @brief 入队
* @return 入队成功返回true 失败返回false 失败是指队列为满
* */
bool EnQueue(const DataType &);
/*
* @brief 出队
* @return 出队成功返回true 失败返回false 失败是指队列为空
* */
bool DeQueue(DataType &);
/*
* @brief 析构函数 释放头结点
* */
~DoubleLockedQueue();
};
template<class DataType>
DoubleLockedQueue<DataType>::DoubleLockedQueue()
{
m_nNum = 0;
}
/*
* @brief 初始化队列容量和头结点
* */
template<class DataType>
void DoubleLockedQueue<DataType>::Init(int max)
{
assert(max > 0 && max <= MAXCAP);
m_nMaxLen = max;
/*
* generate a head node
* */
m_pHead = new QueueNode<DataType>;
m_pTail = this->m_pHead;
}
template<class DataType>
bool DoubleLockedQueue<DataType>::EnQueue(const DataType &data)
{
if(m_nNum.load() >= m_nMaxLen) // 队列满了
{
return false;
}
QueueNode<DataType>*p = new QueueNode<DataType>(data);
++m_nNum;
/*
* 入队与出队的竞争仅仅发生在当队列为空时
* 此时读尾指针与修改尾指针不会同时进行
* 但gcc/g++编译器能够保证对64位地址修改为原子操作
* 例如假设地址A = NULL
* 线程1读取A 线程2修改A
* 那么线程1要么读到NULL 要么读到线程2修改后的地址
* */
lock_guard<mutex>lockguard(m_Tail_Lock);
m_pTail->m_pNext = p;
m_pTail = p;
return true;
}
template<class DataType>
bool DoubleLockedQueue<DataType>::DeQueue(DataType &data)
{
m_Head_Lock.lock();
QueueNode<DataType>*p = m_pHead;
QueueNode<DataType>*newhead = m_pHead->m_pNext; // 此时取头结点的next指针 可能此时入队修改了头结点的next值 但这两个操作不会并行
if(!newhead) { // the queue is empty
m_Head_Lock.unlock();
return false;
}
data = newhead->m_Data;
m_pHead = newhead;
m_Head_Lock.unlock();
--m_nNum;
delete p;
p = NULL;
return true;
}
template<class DataType>
DoubleLockedQueue<DataType>::~DoubleLockedQueue()
{
delete m_pHead;
m_pHead = NULL;
m_pTail = NULL;
}
}
#endif
/*************************************************************************
> File Name: main.cpp
> Author: wangzhicheng
> Mail: 2363702560@qq.com
> Created Time: Sat 31 Dec 2016 09:44:59 AM AWST
************************************************************************/
#include "DoubleLockedQueue.h"
#include <iostream>
#include <thread>
using namespace doublelockedqueue;
DoubleLockedQueue<int>Q;
void func0() {
while(1)
{
for(int i = 0;i < 10;i++) Q.EnQueue(i);
sleep(1);
}
}
void func1() {
while(1)
{
int num;
if(!Q.DeQueue(num)) {
// cerr << "dequeue error...!" << endl;
sleep(1);
continue;
}
else cout << "num = " << num << endl;
}
}
int main()
{
Q.Init(100);
thread th1(func0);
thread th2(func1);
th1.join();
th2.join();
return 0;
}
CC=g++
all:
$(CC) -std=c++11 -g -o DoubleLockedQueueTest main.cpp DoubleLockedQueue.h -pthread -lpthreadDoubleLockedQueue
最新推荐文章于 2021-09-02 08:00:00 发布
本文介绍了一种使用双锁机制实现的并发队列(Double Locked Queue)的设计与实现细节。该队列通过两个互斥锁分别控制入队和出队操作,确保线程安全的同时减少锁竞争。文中提供了完整的C++代码实现,并展示了如何通过多线程测试验证其正确性和性能。

457

被折叠的 条评论
为什么被折叠?



