欢迎来到色坯世界
Time:

您的位置: 首页 >> 天下奇闻 >> 奇闻轶事

buffers-C++高级编程之缓冲区管理

2023.06.20 来源: 浏览:18次

1、缓冲区 MyBuffer.h

MyBuffer类中演示了使用模板编程知识点、运用队列、锁、condition_variable(条件变量,来控制多线程的并发操作)技术来构建一个缓冲区。

#pragma once#ifndef MYBUFFER_H_#define MYBUFFER_H_#include <queue>#include <mutex>#include <memory>// 禁用拷贝构造和赋值操作符以及其移动语义#define OF_DISALLOW_COPY(ClassName)       ClassName(const ClassName&) = delete;   ClassName& operator=(const ClassName&) = delete#define OF_DISALLOW_MOVE(ClassName)   ClassName(ClassName&&) = delete;    ClassName& operator=(ClassName&&) = delete#define OF_DISALLOW_COPY_AND_MOVE(ClassName)   OF_DISALLOW_COPY(ClassName);                 OF_DISALLOW_MOVE(ClassName)// 缓冲区的几种状态enum BufferStatus{	kBufferStatusSuccess = 0,	kBufferStatusErrorClosed,	kBufferStatusEmpty,};template<typename T>class MyBuffer final {public:	// 禁用拷贝和移动语义	OF_DISALLOW_COPY_AND_MOVE(MyBuffer);	MyBuffer(size_t max_len) :max_len_(max_len), is_closed_(false) {}	~MyBuffer() = default;	/*	 * 向队列中添加内容	 **/	BufferStatus Push(const T& item);	/*	 * 获取队列中的内容	 **/	BufferStatus Pull(T* item);	  	BufferStatus TryReceive(T* item);	// 关闭队列的操作	void Close();	  private:	std::queue<T> queue_;	   // 队列	mutable std::mutex mutex_;	// mutex	size_t max_len_;			// 队列最大的个数	bool is_closed_;			// 是否可以对队列进行操作	std::condition_variable cond_;	// 条件变量,控制多线程并发};template<typename T>BufferStatus MyBuffer<T>::Push(const T& item) {	// 加锁,锁住当前线程	std::unique_lock<std::mutex> lock(mutex_);	// 判断lambda表达式是否为TRUE,为TRUE不阻塞,为FALSE阻塞	cond_.wait(lock, [this]() {return queue_.size() < max_len_ || is_closed_; });		// 如果表示已经不允许操作缓冲队列,则返回状态错误	if (is_closed_) { return kBufferStatusErrorClosed; } 	queue_.push(item);	// 唤醒当前线程	// 解除阻塞当前正在等待此条件的线程之一。	// 如果没有线程在等待,则还函数不执行任何操作。如果超过一个,不会指定具体哪一线程。	cond_.notify_one();	 	return kBufferStatusSuccess;}template<typename T>BufferStatus MyBuffer<T>::Pull(T* item) {	std::unique_lock<std::mutex> lock(mutex_);	cond_.wait(lock, [this]() {return (!queue_.empty()) || is_closed_; });	if (queue_.empty()) { return kBufferStatusErrorClosed; }	*item = queue_.front();	queue_.pop();	// 如果当前队列小于最大的队列长度,则唤醒所有的线程	if (queue_.size() < max_len_) { cond_.notify_all(); }	return kBufferStatusSuccess;}template<typename T>BufferStatus MyBuffer<T>::TryReceive(T* item) {	std::unique_lock<std::mutex> lock(mutex_);	if (queue_.empty()) {		return is_closed_ ? kBufferStatusErrorClosed : kBufferStatusEmpty;	}	*item = queue_.front();	queue_.pop();	if (queue_.size() < max_len_) { cond_.notify_all(); }	return kBufferStatusSuccess;}template<typename T>void MyBuffer<T>::Close() {	std::unique_lock<std::mutex> lock(mutex_);	is_closed_ = true;	cond_.notify_all();}#endif

2、缓冲区管理 BufferManager.h

BufferManager类演示如何对上述缓冲区进行管理,采用unordered_map容器来容纳穿冲区,通过给缓冲区起一个名字来索引到具体的缓冲区,使用unique_ptr指针来独占当前缓冲区。

#pragma once#include "MyBuffer.h"#include "Global.hpp"#include <unordered_map>#include <string>// 为unordered_map取别名为HashMaptemplate<typename Key,typename T,typename Hash = std::hash<Key>>using HashMap = std::unordered_map<Key, T, Hash>;// 缓冲区管理template<typename T>class BufferManager final {public:	OF_DISALLOW_COPY_AND_MOVE(BufferManager);	~BufferManager() = default;	// 创建一个新的缓冲区对象	void NewBuffer(const std::string& buffer_name, size_t buffer_size) {		name2Buffer_.emplace(buffer_name, std::make_unique<MyBuffer<T>>(buffer_size)).second;	}	// 获取缓冲区的指针	MyBuffer<T>* Get(const std::string& buffer_name)const {		const auto& iter = name2Buffer_.find(buffer_name);		return iter->second.get();	}private:	friend class Global<BufferManager>;	BufferManager() = default;	// 缓冲区管理对象	HashMap<std::string, std::unique_ptr<MyBuffer<T>>> name2Buffer_;};

3、单例 Global.h

工业级单例程序,用来创建一个单例。

#pragma once// 单例 工业级template<typename T>class Global final {public:	// 获取单例对象	static T* Get() { return *GetPPtr(); }	// 创建单例对象	template<typename... Args>	static void New(Args&&... args) {		assert(Get() == nullptr);		*GetPPtr() = new T(std::forward<Args>(args)...);	}	// 删除单例对象	static void Delete() {		if (Get() != nullptr) {			delete Get();			*GetPPtr() = nullptr;			//std::cout << "删除对象" << std::endl;		}	}private:	static T** GetPPtr() {		static T* ptr = nullptr;		return &ptr;	}};

4、测试类 job_instance.h

用来测试缓冲区的测试类。

#pragma once#include <string>// 测试类class JobInstance {public:	JobInstance() = default;	virtual ~JobInstance() = default;	virtual std::string job_name()const { return "undefined"; }};class PyJobInstance : public JobInstance {public:	using JobInstance::JobInstance;	std::string job_name() const override {		return "job_name";	}};

5、测试例子

测试例子,先构建一个缓冲区管理的单例,根据单例获取缓冲区管理的指针,用缓冲区管理的指针创建一个指定名称和大小的缓冲区。

创建一个测试类的对象,将测试类的对象放入缓冲区中。

通过名称来获取缓冲区的对象,将测试类的对象从缓冲区中拿出来。

关闭缓冲区。

删除单例。

#include "job_instance.h"#include "BufferManager.h"inline std::string GetSourceTickBufferName(const std::string& job_name) {	static const std::string prefix = "SourceTick-";	return prefix + job_name;}void test_my_buffers(){	size_t nSize = 10;	std::string name = "Account";	// 创建一个单例	Global<BufferManager<std::shared_ptr<JobInstance>>>::New();	// 获取单例的指针	auto* buffer_mgr = Global<BufferManager<std::shared_ptr<JobInstance>>>::Get();	// 用单例创建一个名称为Account,大小为nSize的缓冲队列	buffer_mgr->NewBuffer(GetSourceTickBufferName(name), nSize);	// 创建一个对象	std::shared_ptr<JobInstance> cb(new PyJobInstance);	// 将对象放入缓冲队列中	BufferStatus status1 = buffer_mgr->Get(GetSourceTickBufferName(name))->Push(cb);	// 成功的话	if (status1 == kBufferStatusSuccess) {		// 获取缓冲队列中的内容		std::shared_ptr<JobInstance> foreign_job_instance;		BufferStatus status2 = buffer_mgr->Get(GetSourceTickBufferName(name))->TryReceive(&foreign_job_instance);		// 从缓冲队列中获取数据成功,调用对象的方法进行输出信息		if (status2 == kBufferStatusSuccess) {			std::cout << foreign_job_instance.get()->job_name() << std::endl;		}	}	// 关闭缓冲	buffer_mgr->Get(GetSourceTickBufferName(name))->Close();	// 删除单例	Global<BufferManager<std::shared_ptr<JobInstance>>>::Delete();}int main() {	test_my_buffers();}

6、总结

此例子演示了C++高级编程缓冲区管理示例,以及我们如何使用C++的一些高级特性,例如模板类、模板函数、unique_lock、unique_ptr、shared_ptr、锁、临界区、队列、unordered_map等相关知识点,希望这些知识点的综合运用能帮助到各位朋友。

Tags: