Boost lockfree deque 生产者与消费者多对多线程应用
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 生产者与消费者多对多线程应用的更多相关文章
- 练习生产者与消费者-PYTHON多线程中的条件变量同步-Queue
以前练习过,但好久不用,手生,概念也生了, 重温一下.. URL: http://www.cnblogs.com/holbrook/tag/%E5%A4%9A%E7%BA%BF%E7%A8%8B/ ~ ...
- [原创]如何编写多个阻塞队列连接下的多生产者多消费者的Python程序
平常在写程序时,往往会遇到一个需求:在程序的多个阶段都会出现阻塞的可能,因此,这多个阶段就需要并发执行. Python的多线程有一个特点,就是不允许从外部结束一个运行中的线程,这给我们编写代码时带来了 ...
- 玩转Kafka的生产者——分区器与多线程
上篇文章学习kafka的基本安装和基础概念,本文主要是学习kafka的常用API.其中包括生产者和消费者, 多线程生产者,多线程消费者,自定义分区等,当然还包括一些避坑指南. 首发于个人网站:链接地址 ...
- boost::lockfree::queue多线程读写实例
最近的任务是写一个多线程的东西,就得接触多线程队列了,我反正是没学过分布式的,代码全凭感觉写出来的,不过运气好,代码能够work= = 话不多说,直接给代码吧,一个多消费者,多生产者的模式.假设我的任 ...
- 母鸡下蛋实例:多线程通信生产者和消费者wait/notify和condition/await/signal条件队列
简介 多线程通信一直是高频面试考点,有些面试官可能要求现场手写生产者/消费者代码来考察多线程的功底,今天我们以实际生活中母鸡下蛋案例用代码剖析下实现过程.母鸡在鸡窝下蛋了,叫练从鸡窝里把鸡蛋拿出来这个 ...
- java多线程中的生产者与消费者之等待唤醒机制@Version1.0
一.生产者消费者模式的学生类成员变量生产与消费demo,第一版1.等待唤醒: Object类中提供了三个方法: wait():等待 notify():唤醒单个线程 notify ...
- Java 多线程详解(四)------生产者和消费者
Java 多线程详解(一)------概念的引入:http://www.cnblogs.com/ysocean/p/6882988.html Java 多线程详解(二)------如何创建进程和线程: ...
- JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题
JAVA基础再回首(二十五)--Lock锁的使用.死锁问题.多线程生产者和消费者.线程池.匿名内部类使用多线程.定时器.面试题 版权声明:转载必须注明本文转自程序猿杜鹏程的博客:http://blog ...
- JAVA之旅(十五)——多线程的生产者和消费者,停止线程,守护线程,线程的优先级,setPriority设置优先级,yield临时停止
JAVA之旅(十五)--多线程的生产者和消费者,停止线程,守护线程,线程的优先级,setPriority设置优先级,yield临时停止 我们接着多线程讲 一.生产者和消费者 什么是生产者和消费者?我们 ...
随机推荐
- Javascript ——Navigator对象
见 <Javascript 高级程序设计 第二版> P172 一.检测插件: 1.获取所有插件名称: 非IE浏览器:根据plugins数组, function getplugins() { ...
- JSP+Servlet 无数据库模拟登录过程
程序目录结构: index.jsp: <%@ page language="java" contentType="text/html; charset=utf-8& ...
- Android LRUCache
package android.util; import java.util.LinkedHashMap; import java.util.Map; /** * A cache that holds ...
- C# 把一个文件夹下所有文件删除
public static void DelectDir(string srcPath){ try { DirectoryInfo dir = new DirectoryInfo(srcPath); ...
- 2018网络预选赛 徐州H 线段树+树状数组
设读入的数组是a,树状数组用来维护a数组区间和sum,线段树用来维护一个另一个数组ssum的区间和,区间每个点a[i]*(n-i+1),那么l-r的答案是l-r的ssum-(n-r)*(sum[r]- ...
- SpringBoot04 日志框架之Logback
1 日志框架选择 日志门面:SLF4J 日志实现:Logback 2 实现控制台的日志打印输出01 2.1 在需要实现日志信息打印的类中实例化Logger对象 坑01:springBoot项目默认使用 ...
- python pip ez_setup.py
#!/usr/bin/env python """Bootstrap setuptools installation To use setuptools in your ...
- c语言学习笔记-变量、变量的命名、变量的赋值和变量的初始化
在学习了简单的输入输出功能和了解了一些基本的运算符号之后我们可以试着做一个非常简单的计算器. 比如说想计算23+65 输入以下代码就可以了. printf("23+65=%d",2 ...
- JavaScript中的Array.prototype.slice.call()方法学习
JavaScript中的Array.prototype.slice.call(arguments)能将有length属性的对象转换为数组(特别注意: 这个对象一定要有length属性). 但有一个例外 ...
- 并没有看起来那么简单leetcode Generate Parentheses
问题解法参考 它给出了这个问题的探讨. 超时的代码: 这个当n等于7时,已经要很长时间出结果了.这个算法的复杂度是O(n^2). #include<iostream> #include&l ...