boost库中有一个boost::lockfree::queue类型的 队列,对于一般的需要队列的程序,其效率都算不错的了,下面使用一个用例来说明。

  程序是一个典型的生产者与消费者的关系,都可以使用多线程,其效率要比使用上层的互斥锁要快很多,因为它直接使用底层的原子操作来进行同步数据的。

  freedeque.h

 #pragma once#ifndef INCLUDED_UTILS_LFRINGQUEUE
#define INCLUDED_UTILS_LFRINGQUEUE #define _ENABLE_ATOMIC_ALIGNMENT_FIX
#define ATOMIC_FLAG_INIT 0 #pragma once #include <vector>
#include <mutex>
#include <thread>
#include <atomic>
#include <chrono>
#include <cstring>
#include <iostream> // Lock free ring queue template < typename _TyData, long _uiCount = >
class lfringqueue
{
public:
lfringqueue(long uiCount = _uiCount) : m_lTailIterator(), m_lHeadIterator(), m_uiCount(uiCount)
{
m_queue = new _TyData*[m_uiCount];
memset(m_queue, , sizeof(_TyData*) * m_uiCount);
} ~lfringqueue()
{
if (m_queue)
delete[] m_queue;
} bool enqueue(_TyData *pdata, unsigned int uiRetries = )
{
if (NULL == pdata)
{
// Null enqueues are not allowed
return false;
} unsigned int uiCurrRetries = ;
while (uiCurrRetries < uiRetries)
{
// Release fence in order to prevent memory reordering
// of any read or write with following write
std::atomic_thread_fence(std::memory_order_release); long lHeadIterator = m_lHeadIterator; if (NULL == m_queue[lHeadIterator])
{
long lHeadIteratorOrig = lHeadIterator; ++lHeadIterator;
if (lHeadIterator >= m_uiCount)
lHeadIterator = ; // Don't worry if this CAS fails. It only means some thread else has
// already inserted an item and set it.
if (std::atomic_compare_exchange_strong(&m_lHeadIterator, &lHeadIteratorOrig, lHeadIterator))
{
// void* are always atomic (you wont set a partial pointer).
m_queue[lHeadIteratorOrig] = pdata; if (m_lEventSet.test_and_set())
{
m_bHasItem.test_and_set();
}
return true;
}
}
else
{
// The queue is full. Spin a few times to check to see if an item is popped off.
++uiCurrRetries;
}
}
return false;
} bool dequeue(_TyData **ppdata)
{
if (!ppdata)
{
// Null dequeues are not allowed!
return false;
} bool bDone = false;
bool bCheckQueue = true; while (!bDone)
{
// Acquire fence in order to prevent memory reordering
// of any read or write with following read
std::atomic_thread_fence(std::memory_order_acquire);
//MemoryBarrier();
long lTailIterator = m_lTailIterator;
_TyData *pdata = m_queue[lTailIterator];
//volatile _TyData *pdata = m_queue[lTailIterator];
if (NULL != pdata)
{
bCheckQueue = true;
long lTailIteratorOrig = lTailIterator; ++lTailIterator;
if (lTailIterator >= m_uiCount)
lTailIterator = ; //if ( lTailIteratorOrig == atomic_cas( (volatile long*)&m_lTailIterator, lTailIterator, lTailIteratorOrig ))
if (std::atomic_compare_exchange_strong(&m_lTailIterator, &lTailIteratorOrig, lTailIterator))
{
// Sets of sizeof(void*) are always atomic (you wont set a partial pointer).
m_queue[lTailIteratorOrig] = NULL; // Gets of sizeof(void*) are always atomic (you wont get a partial pointer).
*ppdata = (_TyData*)pdata; return true;
}
}
else
{
bDone = true;
m_lEventSet.clear();
}
}
*ppdata = NULL;
return false;
} long countguess() const
{
long lCount = trycount(); if ( != lCount)
return lCount; // If the queue is full then the item right before the tail item will be valid. If it
// is empty then the item should be set to NULL.
long lLastInsert = m_lTailIterator - ;
if (lLastInsert < )
lLastInsert = m_uiCount - ; _TyData *pdata = m_queue[lLastInsert];
if (pdata != NULL)
return m_uiCount; return ;
} long getmaxsize() const
{
return m_uiCount;
} bool HasItem()
{
return m_bHasItem.test_and_set();
} void SetItemFlagBack()
{
m_bHasItem.clear();
} private:
long trycount() const
{
long lHeadIterator = m_lHeadIterator;
long lTailIterator = m_lTailIterator; if (lTailIterator > lHeadIterator)
return m_uiCount - lTailIterator + lHeadIterator; // This has a bug where it returns 0 if the queue is full.
return lHeadIterator - lTailIterator;
} private:
std::atomic<long> m_lHeadIterator; // enqueue index
std::atomic<long> m_lTailIterator; // dequeue index
_TyData **m_queue; // array of pointers to the data
long m_uiCount; // size of the array
std::atomic_flag m_lEventSet = ATOMIC_FLAG_INIT; // a flag to use whether we should change the item flag
std::atomic_flag m_bHasItem = ATOMIC_FLAG_INIT; // a flag to indicate whether there is an item enqueued
}; #endif //INCLUDED_UTILS_LFRINGQUEUE

  

/*
* File: main.cpp
* Author: Peng
*
* Created on February 22, 2014, 9:55 PM
*/
#include <iostream>
#include <string>
#include "freedeque.h"
#include <sstream>
#include <boost/thread/thread.hpp>
#include <boost/lockfree/queue.hpp>
#include <boost/atomic.hpp>
#include<boost/thread/lock_guard.hpp>
#include<boost/thread/mutex.hpp>
#include<boost/date_time/posix_time/posix_time.hpp> const int NUM_ENQUEUE_THREAD = 5;
const int NUM_DEQUEUE_THREAD = 10;
const long NUM_ITEM = 50000;
const long NUM_DATA = NUM_ENQUEUE_THREAD * NUM_ITEM; class Data {
public:
Data(int i = 0) : m_iData(i)
{
std::stringstream ss;
ss << i;
m_szDataString = ss.str();
} bool operator< (const Data & aData) const
{
if (m_iData < aData.m_iData)
return true;
else
return false;
} int& GetData()
{
return m_iData;
}
private:
int m_iData;
std::string m_szDataString;
}; Data* g_arrData = new Data[NUM_DATA];
boost::mutex mtx; constexpr long size = 0.5 * NUM_DATA;
lfringqueue < Data, 10000> LockFreeQueue;
boost::lockfree::queue<Data*> BoostQueue(10000); bool GenerateRandomNumber_FindPointerToTheNumber_EnQueue(int n)
{
for (long i = 0; i < NUM_ITEM; i++)
{
int x = i + NUM_ITEM * n;
Data* pData = g_arrData + x;
LockFreeQueue.enqueue(pData);
}
return true;
} void print(Data* pData) {
if (!pData)
return; boost::lock_guard<boost::mutex> lock(mtx); std::cout << pData->GetData() << std::endl; } bool Dequeue()
{
Data *pData = NULL; while (true)
{
if (LockFreeQueue.dequeue(&pData) && pData)
{
print(pData);
}
else {
boost::thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(5));
}
} return true;
} int main(int argc, char** argv)
{
for (int i = 0; i < NUM_DATA; ++i)
{
Data data(i);
//DataArray[i] = data;
*(g_arrData + i) = data;
} std::thread PublishThread[NUM_ENQUEUE_THREAD];
std::thread ConsumerThread[NUM_DEQUEUE_THREAD];
std::chrono::duration<double> elapsed_seconds; for (int i = 0; i < NUM_ENQUEUE_THREAD; i++)
{
PublishThread[i] = std::thread(GenerateRandomNumber_FindPointerToTheNumber_EnQueue, i);
} for (int i = 0; i < NUM_DEQUEUE_THREAD; i++)
{
ConsumerThread[i] = std::thread{ Dequeue };
} for (int i = 0; i < NUM_DEQUEUE_THREAD; i++)
{
ConsumerThread[i].join();
} for (int i = 0; i < NUM_ENQUEUE_THREAD; i++)
{
PublishThread[i].join();
} delete[] g_arrData;
return 0;
}

  说明:模板文件是原作者写的,为了验证其正确性,后面的测试程序我改写了一下,最后测试程序是无法退出来的,这里只是测试,没有进一步完善了。

  在测试中发现deque应该是大小限制的,再增大data的数据程序会阻塞在某个地方没有进一步再查找原因了,以后有时候再做修改,对于一般的工程都够用了。

Boost lockfree deque 生产者与消费者多对多线程应用的更多相关文章

  1. 练习生产者与消费者-PYTHON多线程中的条件变量同步-Queue

    以前练习过,但好久不用,手生,概念也生了, 重温一下.. URL: http://www.cnblogs.com/holbrook/tag/%E5%A4%9A%E7%BA%BF%E7%A8%8B/ ~ ...

  2. [原创]如何编写多个阻塞队列连接下的多生产者多消费者的Python程序

    平常在写程序时,往往会遇到一个需求:在程序的多个阶段都会出现阻塞的可能,因此,这多个阶段就需要并发执行. Python的多线程有一个特点,就是不允许从外部结束一个运行中的线程,这给我们编写代码时带来了 ...

  3. 玩转Kafka的生产者——分区器与多线程

    上篇文章学习kafka的基本安装和基础概念,本文主要是学习kafka的常用API.其中包括生产者和消费者, 多线程生产者,多线程消费者,自定义分区等,当然还包括一些避坑指南. 首发于个人网站:链接地址 ...

  4. boost::lockfree::queue多线程读写实例

    最近的任务是写一个多线程的东西,就得接触多线程队列了,我反正是没学过分布式的,代码全凭感觉写出来的,不过运气好,代码能够work= = 话不多说,直接给代码吧,一个多消费者,多生产者的模式.假设我的任 ...

  5. 母鸡下蛋实例:多线程通信生产者和消费者wait/notify和condition/await/signal条件队列

    简介 多线程通信一直是高频面试考点,有些面试官可能要求现场手写生产者/消费者代码来考察多线程的功底,今天我们以实际生活中母鸡下蛋案例用代码剖析下实现过程.母鸡在鸡窝下蛋了,叫练从鸡窝里把鸡蛋拿出来这个 ...

  6. java多线程中的生产者与消费者之等待唤醒机制@Version1.0

    一.生产者消费者模式的学生类成员变量生产与消费demo,第一版1.等待唤醒:    Object类中提供了三个方法:    wait():等待    notify():唤醒单个线程    notify ...

  7. Java 多线程详解(四)------生产者和消费者

    Java 多线程详解(一)------概念的引入:http://www.cnblogs.com/ysocean/p/6882988.html Java 多线程详解(二)------如何创建进程和线程: ...

  8. JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题

    JAVA基础再回首(二十五)--Lock锁的使用.死锁问题.多线程生产者和消费者.线程池.匿名内部类使用多线程.定时器.面试题 版权声明:转载必须注明本文转自程序猿杜鹏程的博客:http://blog ...

  9. JAVA之旅(十五)——多线程的生产者和消费者,停止线程,守护线程,线程的优先级,setPriority设置优先级,yield临时停止

    JAVA之旅(十五)--多线程的生产者和消费者,停止线程,守护线程,线程的优先级,setPriority设置优先级,yield临时停止 我们接着多线程讲 一.生产者和消费者 什么是生产者和消费者?我们 ...

随机推荐

  1. SpringMVC—对Ajax的处理(含 JSON 类型)(1)

    一.首先要搞明白的一些事情. 1.从客户端来看,需要搞明白: (1)要发送什么样格式的 JSON 数据才能被服务器端的 SpringMVC 很便捷的处理,怎么才能让我们写更少的代码,如何做好 JSON ...

  2. Java 的基本语法

    Java 语言严格区分大小写 一个 Java 源文件里可以定义多个类,但其中只能有一个类被定义为 public 类 如果源文件中包含了 public 类,源文件的名称必须和该 public 类同名 p ...

  3. webapi中使用token验证(JWT验证)

    本文介绍如何在webapi中使用JWT验证 准备 安装JWT安装包 System.IdentityModel.Tokens.Jwt 你的前端api登录请求的方法,参考 axios.get(" ...

  4. 2016.5.30实现透明Panel及控件置顶的方法

    想放置一个透明Panel在某控件上端,实现效果是可透过此Panel看见下面控件,但鼠标点击却无任何反应. 1.新建置自定义Panel类 using System; using System.Colle ...

  5. Tiny4412 Linux 内核启动流程

    Linux内核的启动分为压缩内核和非压缩内核两种,这里我们以压缩内核为例.压缩内核运行时,将运行一段解压缩程序,得到真正的内核镜像,然后跳转到内核镜像运行.此时,Linux进入非压缩内核入口,在非压缩 ...

  6. PopupWindow-----点击弹出 PopupWindow 初始化菜单

    /** * 点击弹出 PopupWindow 初始化菜单 */ private void initPopupWindow() { PopupWindowAdapter adapter = new Po ...

  7. 使用Eclipse的常见问题整理

    我在Eclipse里新建一个android工程的时候附带着产生了一个名字为appcompat_v7的工程,这个工程是干什么用的啊?为何我新建的工程都出错了,错误信息提示为: error: Error ...

  8. Navicat MySQL安装

    1 下载安装包 点击下载安装包 2 解压安装包(解压后有三个文件) 第一个 Crack 是注册文件 第二个 chinese.rar 是汉化包 第三个 navicat_trial.exe 是安装程序 3 ...

  9. Struts 第一天

    请简述下Struts2 的执行流程. 首先是,启动tomcat服务器,这时候会加载web.xml,当读到filter标签时,会创建过滤器对象.struts2的核心过滤器(StrutsPrepareAn ...

  10. FactoryMethodPattern(23种设计模式之一)

    设计模式六大原则(1):单一职责原则 设计模式六大原则(2):里氏替换原则 设计模式六大原则(3):依赖倒置原则 设计模式六大原则(4):接口隔离原则 设计模式六大原则(5):迪米特法则 设计模式六大 ...