使用元编程进行消息队列管理
Using metaprogramming for message queue management
我正在C++
中实现一个通信机制,该机制是用消息队列和消息类设计的。即抽象父类Message
和类Communication
,其中存在一个方法Communication::send(Message&)
。类Communication
将消息发送到由消息类型决定的适当的消息队列message_queue
。(也就是说,对于Msg1
,它发送给Queue_Msg1
队列,Msg2
发送给Queue_Msg2
队列)每个消息类型都将作为Message
的派生类创建。
主要是,我对自动创建队列感兴趣。也就是说,如果我决定添加一个新的消息类型类newMsg
,那么添加消息队列Queue_newMsg
的过程将不需要更改Communication
类中的代码,例如为每个消息类型创建队列的代码。
由于这可以在编译时完成(在编译时,所有派生的消息类都是已知的,因此需要消息队列),因此我试图考虑一些元编程解决方案,但没有设法找到这样的解决方案。
使用一些已知的MPL,如boost/mpl
,我如何实现上述目标?
将您的类型打包成列表:
template<typename... Ts>
struct type_list {};
使用该列表和参数包解包来创建队列的std::array
。如果您希望队列本身具有特定的类型,则需要将它们放在tuple
中。
上面的列表暗示了索引和类型之间的双向映射。让每种类型的实例返回索引,您可以使用索引来获取队列(在数组中很容易——在tuple
中需要更多的工作)。
一个index_of
特征类,在type_list<Ts...>
中查找T
类型的索引:
template<typename T, typename list, typename=void>
struct index_of {};
template<typename T, typename T0, typename... Ts>
struct index_of<T, type_list<T0, Ts...>,
typename std::enable_if<std::is_same<T, T0>::value>::type
> : std::integral_constant<size_t, 0>
{};
template<typename T, typename T0, typename... Ts>
struct index_of<T, type_list<T0, Ts...>,
typename std::enable_if<!std::is_same<T, T0>::value>::type
> : std::integral_constant<size_t,
index_of<T, type_list<Ts...>>::value+1>
{};
可能实现基于CRTP的"消息助手",实现GetTypeIndex
并确保您的类型在中心消息列表中。
这需要c++ 11,在c++ 03中更难,也更有限。一个c++ 11编译器也可以处理100个类型,而不需要做太多额外的模板元编程(严格的元编程,至少在理论上,1000个或更多),而一个c++ 03编译器即使有一个健壮的元编程库,也可能被限制在10个类型。
请注意,这种方法的一个优点是,理论上,您可以完全取消抽象父类,或者至少取消sendMessage( message const& m )
接口(为什么允许人们发送抽象消息?)您可能只被允许发送实际的具体消息类型。这同样需要更多的工作(创建使用CRTP获取队列的包扩展继承树)。
struct MessageBase {
virtual size_t GetTypeIndex() const = 0;
};
template<typename D, typename List>
struct MessageHelper: public MessageBase {
static_assert( std::is_base_of< MessageHelper<D,List>, D >::value, "MessageHelper<D> must be inherited from by D" );
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D const*>(this); }
virtual size_t GetTypeIndex() const final override {
return index_of<D,List>::value;
}
};
struct A_Queue {
std::deque< std::unique_ptr<MessageBase> > data;
};
template<typename type_list>
struct MessageQueues;
template<typename... Ts>
struct MessageQueues<type_list<Ts...>> {
std::array< A_Queue, sizeof...(Ts) > queues;
void Enqueue( std::unique_ptr<MessageBase> msg ) {
size_t index = msg->GetTypeIndex();
queues[ index ].data.push-back( std::move(msg) );
}
};
您可以在运行时注册不同的消息类型,而不是依赖于元编程。注册中心可以创建队列向量并提供唯一标识符,以最小化查找成本,或者如果您不太关心这一点,您可以始终使用从某个id到适当队列的映射。
虽然我不推荐它,但如果你真的想写一个复杂的模板解决方案,你可以看看类型列表。你需要的所有构建块都在Alexandrescu的Modern c++ Design中(类型列表,如何从中构建层次结构,以及一些花哨的模板技巧)。
- boost::进程间消息队列引发错误
- 避免使用 boost::进程间::消息队列创建文件
- 提升消息队列 跨两个进程未接收
- 可以将Boost消息队列文件重定向到用户指定的位置
- 使用加速进程间创建消息队列 - 内存访问冲突
- 如何检查提升消息队列是否存在
- Win32 消息队列在使用 OpenGL 渲染时被淹没
- 在尝试使用boost时断言.跨很多过程中的互动消息队列
- GetMessage/PeekMessage - 删除消息队列中的所有消息
- IPC Unix 消息队列线程安全吗?
- 在.c文件接收函数中使用Linux中的MSGGET创建消息队列未实现错误
- boost消息队列线程安全和进程安全吗?
- 为什么我的无锁消息队列段错误:(?
- 在控制台应用程序中处理空的windows消息队列
- 关于在这种情况下消息队列与共享内存的适用性或适用性
- boost::进程间消息队列创建时的竞争条件
- 从内存转储中查找线程消息队列中的消息
- win32消息泵,do dispatchMessage()处理整个消息队列或仅仅是顶部消息
- 如何使用Boost进程间消息队列for Windows
- 来自另一个线程的 SendMessage() 调用是否将消息发布到消息队列