Eventbus实现
1. 事件总线
用于多线程操作,降低库与库之间的耦合,提高执行效率。
2. 任意类型参数
当你需要一个可变的类型时,有三种可能的解决方案:
- 无限制的类型,如 void*. 这种方法不可能是类型安全的,应该象逃避灾难一样避免它。
- 可变的类型,即支持多种类型的存储和获取的类型。
- 支持转换的类型,如字符串类型与整数类型之间的转换。
解决方法:使用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);
}
参考: