concurrentqueue助我实现GenTL的AcquisitionChain

concurrentqueue助我实现GenTL的AcquisitionChain
请添加图片描述

该图来自GenTL的从Buffer角度的采集链路图。此图中有两处用到了队列,我们可以将下面的Input Buffer Pool/Output Buffer Queue/Fill 节点稍微细节一下变成如下图的架构
请添加图片描述

上图更为清晰的发现在Input/Output上使用了队列的技术,手写简单的队列没有问题,但是符合工业级的无锁队列就要请出功臣moodycamel::ConcurrentQueue,以下是该队列的主要特点

  • 超快性能,让人瞠目结舌

  • 单头实现。只需将其放入项目中即可

  • 完全线程安全的无锁队列。可由任意数量的线程并发使用

  • C++11 实现 – 尽可能移动元素(而不是复制)

  • 模板化,无需专门处理指针–内存由专人管理

  • 对元素类型或最大数量没有人为限制

  • 内存可以预先分配一次,也可以根据需要动态分配

  • 完全可移植(无需汇编;所有操作均通过标准 C++11 基元完成)

  • 支持超快的批量操作

  • 包括低开销阻塞版本(BlockingConcurrentQueue)

  • 异常安全

1、moodycamel::ConcurrentQueue主要基本用法

#include <iostream>
#include <string>
#include <memory>
#include <map>
#include "blockingconcurrentqueue.h"

struct demoStruct {
	int intV;
	float floatV;
	double doubleV;
	std::string stringV;
	void* pointerV;
	std::size_t sizeV;
};

class demoClass {
public:
	demoClass() = default;
	demoClass(int a, float b, double c, std::string d, std::size_t e) :
		intV(a), floatV(b), doubleV(c), stringV(d), sizeV(e), pointerV(nullptr), name(d) {}
	void test() {}
	void test2() {}
private:
	demoClass(demoClass &);// forbidden
	demoClass &operator=(const demoClass &);
	std::string name;
	int intV;
	float floatV;
	double doubleV;
	std::string stringV;
	void* pointerV;
	std::size_t sizeV;
};

int main()
{
	// 存放基本类型
	moodycamel::ConcurrentQueue<int> q;
	for (int i = 0; i != 123; ++i)
		q.enqueue(i);

	int item;
	for (int i = 0; i != 123; ++i) {
		q.try_dequeue(item);
		std::cout << item << std::endl;
		assert(item == i);
	}
	q.size_approx();

	// 存放结构体
	moodycamel::ConcurrentQueue<demoStruct> structQ;
	demoStruct q1;
	q1.doubleV = 3.00f;
	q1.floatV = 1.00f;
	q1.intV = 2;
	q1.pointerV = nullptr;
	q1.sizeV = 23;
	q1.stringV = "hello";
	structQ.enqueue(q1);

	demoStruct q2;
	structQ.try_dequeue(q2);

	// BlockingConcurrentQueue使用
	moodycamel::BlockingConcurrentQueue<int> intq;
	intq.enqueue(1);
	std::cout << intq.size_approx() << std::endl;
	{
		moodycamel::BlockingConcurrentQueue<int> otherq;
		intq.swap(otherq);
	}
	std::cout << intq.size_approx() << std::endl;

	// BlockingConcurrentQueue存放类
	moodycamel::BlockingConcurrentQueue<std::shared_ptr<demoClass>> scq;
	std::shared_ptr<demoClass> sc = std::make_shared<demoClass>(1, 2.0, 3.0f, "hello world", 123);
	scq.enqueue(sc);
	std::shared_ptr<demoClass> sc2;
	scq.try_dequeue(sc2);

	// BlockingConcurrentQueue超时机制
	moodycamel::BlockingConcurrentQueue<int> cq;
	std::thread reader([&]() {
		int item;
#if 0
		for (int i = 0; i != 100; ++i) {
			// Fully-blocking:
			q.wait_dequeue(item);
		}
#else
		for (int i = 0; i != 100; ) {
			// Blocking with timeout
			if (cq.wait_dequeue_timed(item, std::chrono::milliseconds(6))) {
				std::cout << item << std::endl;
				++i;
			}
		}
#endif
	});
	std::thread writer([&]() {
		for (int i = 0; i != 100; ++i) {
			cq.enqueue(i);
			std::this_thread::sleep_for(std::chrono::milliseconds(5));
		}
	});
	writer.join();
	reader.join();

	return 0;
}

2、使用moodycamel::ConcurrentQueue简易实现图二

#include <iostream>
#include <thread>
#include "blockingconcurrentqueue.h"

class Buffer
{
public:
	Buffer() {}
	void SetBaseAddr(uint64_t baseAddr) {
		anologBaseAddr = baseAddr;
	}
	uint64_t GetBaseAddr()
	{
		return anologBaseAddr;
	}
	void SetDataSize(size_t dataSize) {
		size = dataSize;
	}
	size_t GetDataSize() {
		return size;
	}
private:
	Buffer(Buffer &); // forbidden
	Buffer &operator=(const Buffer &); // forbidden

private:
	uint64_t anologBaseAddr;// 模拟地址
	size_t size; // 数据大小
};

moodycamel::BlockingConcurrentQueue<std::shared_ptr<Buffer>> inputQueue;
moodycamel::BlockingConcurrentQueue<std::shared_ptr<Buffer>> outputQueue;
static uint64_t address = 0x00000000001;

int main()
{
    std::cout << "Hello World!\n";
	// fill buffer 
	std::thread FillBufferThread([]() {
		while (true) {
			std::shared_ptr<Buffer> newBuffer;
			// input queue -> filling
			inputQueue.wait_dequeue(newBuffer);
			newBuffer->SetBaseAddr(address++);
			newBuffer->SetDataSize(10 * 1024);
			std::this_thread::sleep_for(std::chrono::seconds(2));
			std::cout << "Filled " << address << " OK" << std::endl;
			// filled -> output queue
			outputQueue.enqueue(newBuffer);
		}
	});
	// op buffer 
	std::thread OpBuffer([]() {
		while (true) {
			std::shared_ptr<Buffer> newBuffer;
			std::cout << "Waiting Filled Buffer" << std::endl;
			// output queue -> op
			outputQueue.wait_dequeue(newBuffer);
			std::this_thread::sleep_for(std::chrono::seconds(1));
			std::cout << "Op Buffer " << newBuffer->GetBaseAddr() << " size " << newBuffer->GetDataSize() << std::endl;
			// queue buffer -> input queue
			inputQueue.enqueue(newBuffer);
		}
	});

	for (size_t idx = 0; idx < 4; ++idx) {
		// announce
		std::shared_ptr<Buffer> newBuffer = std::make_shared<Buffer>();
		// queuebuffer -> input queue
		inputQueue.enqueue(newBuffer);
	}

	FillBufferThread.join();
	OpBuffer.join();
	return 0;
}
  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值