C/C++开发,c++线程通信-构建另类的线程间数据传输信道

目录

一、单体类消息队列概念

二、源码实现

        2.1 消息队列

        2.2 线程锁

三、 接口调用


一、单体类消息队列概念

        c++线程之间通信方式多种多样,诸如全局变量、回调函数、事件通知、信号通知、管道等等,下面为大家介绍一种本人在项目实践过常用并使用的一种线程通信方式,该通信方式主要仿消息队列实现一种类全局变量或线程变量的队列类。

        单体类很多时候可以实现全局变量的效果,通过单体类+队列容器+线程锁可以快速构建线程之间的数据通道,达到安全通信的目的。

二、源码实现

        下面给出该队列类QueueDataSingle的实现代码,是一个单体类模板,其继承父类QueueData,通过容器deque进行数据存储,并定义了线程锁PYMutex进行安全限制:

        2.1 消息队列

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#ifndef _QUEUE_DATA_H_
#define _QUEUE_DATA_H_

/***********************************************************************
  *Copyright 2020-03-06, pyfree
  *
  *File Name       : queuedata.h
  *File Mark       : 
  *Summary         : 
  *数据队列类,线程安全
  *
  *Current Version : 1.00
  *Author          : pyfree
  *FinishDate      :
  *
  *Replace Version :
  *Author          :
  *FinishDate      :

 ************************************************************************/
#include <queue>
#include <deque>
#include <stdio.h>
#include <string.h>

#include "Mutex.h"

template <class T>
class QueueData
{
public:
	QueueData(std::string desc = "thread_queue");
	~QueueData();
	//
	/**
	 * 获取队列大小
	 * @return {int } 队列大小
	 */
	int size();
	/**
	 * 判定队列是否为空
	 * @return {bool } 是否为空队列
	 */
	bool isEmpty();
	/**
	 * 获取队列头元素
	 * @param it {T&} 头元素
	 * @return {bool } 是否成功
	 */
	bool getFirst(T &it);
	/**
	 * 删除元素
	 * @return {bool } 是否成功
	 */
	bool removeFirst();
	/**
	 * 获取队列头元素,并从队列终删除
	 * @param it {T&} 头元素
	 * @return {bool } 是否成功
	 */
	bool pop(T &it);
	/**
	 * 从队列头开始逐步获取多个元素,并剔除
	 * @param its {queue<T>&} 获取到的元素集
	 * @param sizel {int} 一次获取多少个
	 * @return {bool } 至少获取一个元素以上则成功
	 */
	bool getList(std::queue<T> &its,unsigned int sizel=5);
	/**
	 * 从队列尾部添加元素
	 * @param it {T} 被添加元素
	 * @return {void } 无返回
	 */
	void add(T it);
	/**
	 * 从队列头部添加元素
	 * @param it {T} 被添加元素
	 * @return {void } 无返回
	 */
	void add_front(T it);
	/**
	 * 清空元素
	 * @return {void }
	 */
	void clear();
private:
	void init();
	QueueData& operator=(const QueueData&) {return this;};
protected:
	std::string queue_desc;
private:
	std::deque<T> datacache_queue;	//队列容器
	PYMutex m_Mutex;				//线程锁,或者如果更彻底采用acl库,采用acl::thread_mutex替代
	//
	static unsigned int QSize;		//队列大小约束,超出是会从队列头剔除旧数据腾出空位在对末添加数据
	//
	int queue_overS;				//队列溢出次数计数
};
template <class T>
unsigned int  QueueData<T>::QSize = 100;

template <class T>
QueueData<T>::QueueData(std::string desc)
	: queue_desc(desc)
{
	init();
};

template <class T>
void QueueData<T>::init() 
{
	queue_overS = 0;
};

template <class T>
QueueData<T>::~QueueData()
{

}

//
template <class T>
int QueueData<T>::size()
{
	int ret = 0;
	m_Mutex.Lock();
	ret = static_cast<int>(datacache_queue.size());
	m_Mutex.Unlock();
	return ret;
}

template <class T>
bool QueueData<T>::isEmpty()
{
	bool ret = false;
	m_Mutex.Lock();
	ret = datacache_queue.empty();
	m_Mutex.Unlock();
	return ret;
}

template <class T>
bool QueueData<T>::getFirst(T &it) 
{
	bool ret = false;
	m_Mutex.Lock();
	if (!datacache_queue.empty()) 
	{
		it = datacache_queue.front();
		ret = true;
	}
	m_Mutex.Unlock();
	return ret;
}

template <class T>
bool QueueData<T>::removeFirst() 
{
	bool ret = false;
	m_Mutex.Lock();
	if (!datacache_queue.empty()) 
	{
		datacache_queue.pop_front();
		ret = true;
	}
	m_Mutex.Unlock();
	return ret;
}

template <class T>
bool QueueData<T>::pop(T &it)
{
	bool ret = false;
	m_Mutex.Lock();
	if (!datacache_queue.empty()) 
	{
		it = datacache_queue.front();
		datacache_queue.pop_front();
		ret = true;
	}
	m_Mutex.Unlock();
	return ret;
};

template <class T>
bool QueueData<T>::getList(std::queue<T> &its,unsigned int sizel)
{
	m_Mutex.Lock();
	while (!datacache_queue.empty())
	{
		its.push(datacache_queue.front());
		datacache_queue.pop_front();
		if (its.size() >= sizel)
		{
			break;
		}
	}
	m_Mutex.Unlock();
	return !its.empty();
};

template <class T>
void QueueData<T>::add(T it) 
{
	m_Mutex.Lock();
	if (datacache_queue.size() > QSize) 
	{
		queue_overS++;
		datacache_queue.pop_front();
	}
	datacache_queue.push_back(it);
	m_Mutex.Unlock();
	if (queue_overS >= 10) 
	{
		//每溢出10次,报告一次
		printf("add item to queue %s at end,but the size of QueueData is up to limmit size: %d .[%s %s %d]\n"
			, queue_desc.c_str(), QSize
			, __FILE__, __FUNCTION__, __LINE__);
		queue_overS = 0;
	}
}

template <class T>
void QueueData<T>::add_front(T it)
{
	m_Mutex.Lock();
	if (datacache_queue.size() > QSize) 
	{
		queue_overS++;
		datacache_queue.pop_front();
	}
	datacache_queue.push_front(it);
	m_Mutex.Unlock();
	if (queue_overS >= 10) 
	{
		//每溢出10次,报告一次
		printf("add item to queue %s at first,but the size of QueueData is up to limmit size: %d .[%s %s %d]\n"
			, queue_desc.c_str(), QSize
			, __FILE__, __FUNCTION__, __LINE__);
		queue_overS = 0;
	}
}

template <class T>
void QueueData<T>::clear()
{
	m_Mutex.Lock();
	datacache_queue.clear();
	m_Mutex.Unlock();
	queue_overS = 0;
}

#endif //_QUEUE_DATA_H_

        其继承父类代码:

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#ifndef _QUEUE_DATA_SINGLE_H_
#define _QUEUE_DATA_SINGLE_H_

/***********************************************************************
  *Copyright 2020-03-06, pyfree
  *
  *File Name       : queuedata_single.h
  *File Mark       : 
  *Summary         : 
  *单体类数据队列,线程安全,具体实现在其父类QueueData<T>
  *
  *Current Version : 1.00
  *Author          : pyfree
  *FinishDate      :
  *
  *Replace Version :
  *Author          :
  *FinishDate      :

 ************************************************************************/
#include "queuedata.h"

template <class T>
class QueueDataSingle : public QueueData<T>
{
public:
	static QueueDataSingle* getInstance();
	static void Destroy();
	~QueueDataSingle();

	void setQueueDesc(std::string desc);
private:
	QueueDataSingle(std::string desc="single_thread_queue") 
		: QueueData<T>(desc)
	{
	};
	QueueDataSingle& operator=(const QueueDataSingle&) {return this;};
private:
	static QueueDataSingle* instance;
};

template <class T>
QueueDataSingle<T>* QueueDataSingle<T>::instance = NULL;

template <class T>
QueueDataSingle<T>* QueueDataSingle<T>::getInstance()
{
	if (NULL == QueueDataSingle::instance)
	{
		QueueDataSingle::instance = new QueueDataSingle();
	}
	return QueueDataSingle::instance;
}

template <class T>
void QueueDataSingle<T>::Destroy()
{
	if (NULL != QueueDataSingle::instance) 
	{
		delete QueueDataSingle::instance;
		QueueDataSingle::instance = NULL;
	}
}

template <class T>
QueueDataSingle<T>::~QueueDataSingle()
{

}

template <class T>
void QueueDataSingle<T>::setQueueDesc(std::string desc)
{
	this->queue_desc = desc;
}

#endif //_QUEUE_DATA_SINGLE_H_

        2.2 线程锁

        队列类依赖的线程锁实现代码如下:

        Mutex.h

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#ifndef _PYMUTEX_H_
#define _PYMUTEX_H_

/***********************************************************************
  *Copyright 2020-03-06, pyfree
  *
  *File Name       : Mutex.h
  *File Mark       : 
  *Summary         : 线程锁
  *
  *Current Version : 1.00
  *Author          : pyfree
  *FinishDate      :
  *
  *Replace Version :
  *Author          :
  *FinishDate      :

 ************************************************************************/

#ifdef WIN32
//#include <windows.h>
#else
#include <pthread.h>
#endif

typedef void *HANDLE;

class IMutex
{
public:
	virtual ~IMutex() {}

  /**
	 * 上锁
	 * @return {void} 
	 */
	virtual void Lock() const = 0;
  /**
	 * 尝试上锁
	 * @return {void} 
	 */
	virtual bool TryLock() const = 0;
  /**
	 * 解锁
	 * @return {void} 
	 */
	virtual void Unlock() const = 0;
};

class PYMutex : public IMutex
{
public:
	PYMutex();
	~PYMutex();

	virtual void Lock() const;
	virtual bool TryLock() const;
	virtual void Unlock() const;
private:
#ifdef _WIN32
	HANDLE m_mutex;
#else
	mutable pthread_mutex_t m_mutex;
#endif
};

#endif //_PYMUTEX_H_

        Mutex.cpp

#include "Mutex.h"

#ifdef WIN32
#include <windows.h>
#endif
//#include <iostream>
#include <stdio.h>

PYMutex::PYMutex()
{
#ifdef _WIN32
	m_mutex = ::CreateMutex(NULL, FALSE, NULL);
#else
	pthread_mutex_init(&m_mutex, NULL);
#endif
}


PYMutex::~PYMutex()
{
#ifdef _WIN32
	::CloseHandle(m_mutex);
#else
	pthread_mutex_destroy(&m_mutex);
#endif
}


void PYMutex::Lock() const
{
#ifdef _WIN32
	//DWORD d = WaitForSingleObject(m_mutex, INFINITE);
	WaitForSingleObject(m_mutex, INFINITE);
	/// \todo check 'd' for result
#else
	pthread_mutex_lock(&m_mutex);
#endif
}

bool PYMutex::TryLock() const
{
#ifdef _WIN32
    DWORD dwWaitResult = WaitForSingleObject(m_mutex, 0);  
	if (dwWaitResult != WAIT_OBJECT_0 && dwWaitResult != WAIT_TIMEOUT) {
		printf("thread WARNING: bad result from try-locking mutex\n");
	}
    return (dwWaitResult == WAIT_OBJECT_0) ? true : false; 
#else
	return (0==pthread_mutex_trylock(&m_mutex))?true:false;
#endif	
};

void PYMutex::Unlock() const
{
#ifdef _WIN32
	::ReleaseMutex(m_mutex);
#else
	pthread_mutex_unlock(&m_mutex);
#endif
}

三、 接口调用

        定义了队列类后,下来我们看看其应用,以下为伪代码:

struct wd
{
    int a;
    float b;
};

thread01:

QueueDataSingle<wd> *queue_=QueueDataSingle<wd>::getInstance();
queue_->setQueueDesc("my_write_queue");

run:

wd it = //your code

queue_->add(it);


thread02:

QueueDataSingle<wd> *queue_=QueueDataSingle<wd>::getInstance();

wd it;
if(queue_->pop(it))
{
    //your code
}

or:
if(queue_->getFirst(it))
{
    //your code
    //for some condition
    if(!queue_->removeFirst())
    {
        //
    }
}

        由于队列类是单体类,甚至不必将其声明为线程类的变量,直接在某个需要使用的函数内直接即时声明即时使用,很便捷,另外其父类QueueData可以用在线程类某些场景下作为数据缓存使用,例如在sokcet通信读取时,优先将数据丢到缓存,业务解析处理根据线程资源另行处理,会给socket通信效率带来优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

py_free-物联智能

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值