c++事件总线简单实现

1. 事件总线

用于多线程操作,降低库与库之间的耦合,提高执行效率。

2. 任意类型参数

当你需要一个可变的类型时,有三种可能的解决方案:

  1. 无限制的类型,如 void*. 这种方法不可能是类型安全的,应该象逃避灾难一样避免它。
  2. 可变的类型,即支持多种类型的存储和获取的类型。
  3. 支持转换的类型,如字符串类型与整数类型之间的转换。

解决方法:使用boost::Any

boost::Any的一个重要特性是,它提供了存储不同类型的对象到标准库容器中的能力。它也是一种可变数据类型,这正是C++标准库非常需要而又缺乏的。

用法
any 只允许你在知道类型的前提下访问它的值:

  • 头文件 <boost/any.hpp>

  • 模板函数 any_cast:

      template<typename ValueType>  ValueType any_cast(const any& operand);
      any_cast 让你访问any中存放的值。参数为需要取回值的 any 对象。
      如果类型 ValueType 与所存值不符,any 抛出一个 bad_any_cast 异常。
      请注意,这个语法有点象 dynamic_cast.
      
      template<typename ValueType>  const ValueType* any_cast(const any* operand);
      any_cast 的一个重载,接受一个指向 any 的指针,并返回一个指向所存值的const指针。
      如果 any 中的类型不是 ValueType, 则返回一个空指针。
    
      template<typename ValueType>  ValueType* any_cast(any* operand);
      any_cast 的另一个重载,与前一个版本相似
    

3. 注册机制

4. 线程处理

使用boost::thread:

class HelloWorld
{
public:
 	void hello(const std::string& str)
 	{
        std::cout<<str;
	}; 
}

int main(int argc, char* argv[])
{ 
 	HelloWorld obj;
	boost::function f =  
		boost::bind(&HelloWorld::hello,&obj,"Hello world");
 	boost::thread thrd(f) ;
 	thrd.join();
 	return 0;
}

线程局部存储:

Boost线程库提供了智能指针boost::thread_specific_ptr来访问本地存储线程。每一个线程第一次使用这个智能指针的实例时,它的初值是NULL,所以必须要先检查这个它的只是否为空,并且为它赋值。Boost线程库保证本地存储线程中保存的数据会在线程结束后被清除。

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/tss.hpp>
#include <iostream>
 
boost::mutex io_mutex;
boost::thread_specific_ptr<int> ptr;//线程局部变量
 
struct count
{
	count(int id) : id(id) { }
 
	void operator()()
	{
		if (ptr.get() == 0)//初始化
			ptr.reset(new int(0));
 
		for (int i = 0; i < 10; ++i)
		{
			(*ptr)++;
			boost::mutex::scoped_lock lock(io_mutex);
			std::cout << id << ": "	<< *ptr << std::endl;
		}
	}
 
	int id;
};
 
int main(int argc, char* argv[])
{
	boost::thread thrd1(count(1));
	boost::thread thrd2(count(2));
	thrd1.join();
	thrd2.join();
	return 0;
}

5. BOOST库链接时提示找不到“libxxx”

编译BOOST库时,可以生成动态库或静态库,BOOST默认使用静态库链接,而且可以自动链接,但是用动态库时,需要加入宏:BOOST_ALL_DYN_LINK

bjam stage –toolset=msvc-10.0–without-python 
stagedir="D:/SDK/boost_1.60/vs2010" link=shared 
runtime-link=shared threading=multi debug release

所以推荐,使用静态库链接BOOST

6. multimap用法

插入用insert(make_pair(K,V))

找到所有以“mk”为键的值

RetRange range = _eventMap.equal_range(“mk”);
for (constItr itr = range.first; itr != range.second; ++itr)
{
	...
}

删除:

iterator  erase (const_iterator position);//删除某个位置的元素
size_type erase (const key_type& k);//删除所有以K为键的元素
iterator  erase (const_iterator first, const_iterator last);

7.事件总线简单实现

.h

#include <string>
#include <map>
#include <vector>
#include <boost/function.hpp>
#include <boost/any.hpp>
#include "SingleApp.h"


/* 事件*/
class IEvent
{
public:
	enum EventType{
		type_async =0,
		type_sync,
	};

public:
	IEvent(const int & id, int pri=127, EventType type= type_async);
	IEvent(const IEvent & other);
	IEvent & operator=(const IEvent & other);
	bool operator ==(const IEvent & other)const;
	bool operator < (const IEvent & other)const;

private:
	int _id;
	int _priority;
	EventType _type;
};


//处理仿函数
struct IHandler
{
	boost::any _param;
};
//处理的仿函数定义
typedef boost::function<void(boost::any)> Func;
typedef std::multimap<IEvent, Func > HandlerMap;	//事件地图
typedef HandlerMap::const_iterator constItr;
typedef std::pair<constItr,constItr> RetRange;	//查找结果


/* 事件总线*/
class EventBus: public SingleApp<EventBus>
{
public:
	EventBus(void);
	~EventBus(void);

public:

	/************************************************************************/
	/* 订阅事件
		e:事件类型
		Func:事件的处理函数,用boost::bind(&X::f, this, _1)
	*/
	/************************************************************************/
	void Subscribe(const IEvent & e, Func & handler);

	/************************************************************************/
	/*  Post事件
		e:事件
		IHandler:参数
	*/
	/************************************************************************/
	void Post(const IEvent & e, const IHandler & param);

	/************************************************************************/
	/* 取消订阅事件
	*/
	/************************************************************************/
	void UnSubscribe(const IEvent & e);

private:
	HandlerMap _eventMap;
};

.cpp

#include "EventBus.h"
#include <boost/bind.hpp>
#include <boost/thread/thread.hpp>


IEvent::IEvent( const int & id, int pri/*=127*/, EventType type/*= type_async*/ )
{
	_id = id;
	_priority = pri;
	_type = type;
}

IEvent::IEvent( const IEvent & other )
{
	if (this == & other)
	{
		return;
	}
	else
	{
		this->_id = other._id; 
		this->_priority = other._priority;
		this->_type = other._type;
	}
}

IEvent & IEvent::operator=( const IEvent & other )
{
	if (this == & other)
	{
		return *this;
	}

	this->_id = other._id; 
	this->_priority = other._priority;
	this->_type = other._type;
	return *this;
}


bool IEvent::operator==( const IEvent & other ) const
{
	if (this->_id == other._id && 
		this->_priority== other._priority &&
		this->_type == other._type)
	{
		return true;
	}
	return false;
}

bool IEvent::operator<( const IEvent & other ) const
{
	if (this->_id < other._id )
	{
		return true;
	}
	return false;
}

EventBus::EventBus(void)
{

}

EventBus::~EventBus(void)
{
}

void EventBus::Subscribe(const IEvent & e, Func & handler )
{
	_eventMap.insert(std::make_pair(e,handler));
}

void EventBus::Post( const IEvent & e, const IHandler & param )
{
	RetRange range = _eventMap.equal_range(e);
	for (constItr itr = range.first; itr != range.second; ++itr)
	{
		Func f = itr->second;
		boost::thread thread(f, param._param);
	}
}

void EventBus::UnSubscribe( const IEvent & e )
{
	_eventMap.erase(e);
}

参考:

  1. my coding.net
  2. 定义
  3. boost.any实现任意类型存储
  4. 基于Boost 的线程安全队列
  5. boost提供的几种lock-free方案以及std::atomic实现无锁队列
  6. boost::thread的六种使用方法总结
  7. 理解线程局部存储区
  8. 每天进步一点点——Linux中的线程局部存储(一)
  9. boost线程局部存储
  10. STL里的multimap使用简介
  11. http://www.cplusplus.com/reference/map/multimap/multimap/
  12. 事件总线(Event Bus)知多少
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

baibingql

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

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

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

打赏作者

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

抵扣说明:

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

余额充值