许多RTOS消息传递示例显示了生产者生成的内容与int32一样简单,并且消费者正在读取它。这很简单,因为您总是知道从队列(或其他消息传递缓冲区)中出来的类型以及大小。
考虑使用RTOS线程从GPS读取数据的情况。 GPS可能包含许多类型的消息。您无法保证消息何时到达,消息的顺序或消息的大小。每条消息都有许多字段,每条消息都可以表示为一个结构。
这个GPS处理生产者RTOS线程理想地将数据流解析进来,然后将数据传递出去,以便消费者线程可以轻松读取GPS数据。
假设FreeRTOS或CMSIS RTOS。如何最好地建立这种安排?将使用哪些原语?从根本上讲,我正在寻找一种干净的方法,可以将几种不同类型的不同大小的结构从生产者线程中传递出来,并在使用者中读取它们。
答案 0 :(得分:4)
FreeRTOS文档与QueueSet一起讨论了该问题。 (请参阅“使用队列集的替代方法”一节中的https://www.freertos.org/Pend-on-multiple-rtos-objects.html)。 基本上,这个想法是要有一个枚举来标识缓冲区中不同类型的消息。
对于您的缓冲区类型,可以结合使用枚举和结构体联合。
count
然后您可以区分以下消息:
struct A {uint32_t foo;};
struct B {uint8_t bar;};
enum T {AType, BType};
struct GenericMessage{
T type;
union{
struct A a;
struct B b;
};
};
答案 1 :(得分:3)
您可能会考虑使用指向消息的指针队列,而不是使用消息本身队列。这样,不管消息是什么,队列中的每个项目都是固定大小(指针大小)。
该技术确实需要仔细的资源管理,以确保在接收者处理完消息之前,不对消息进行修改,删除或重用。您需要一个allocate-enqueue-dequeue-deallocate机制。
例如,给定:
enum eMessageType
{ AType,
BType
};
struct GenericMessage
{
eMessageType type;
char payload[0] ; // Note GCC zero-length array extension
};
struct A { struct GenericMessage,
uint32_t foo;
};
struct B { struct GenericMessage,
uint8_t bar;
};
然后,发件人可能会有类似(伪代码)的内容:
struct A* messageA = allocateMessageA( AType, 0x12345678 ) ;
struct B* messageB = allocateMessageB{ BType, 0x12 } ;
sendGeneric( genericQ, messageA ) ;
sendGeneric( genericQ, messageB ) ;
和接收方:
struct GenericMessage* message_ptr = receiveGeneric( genericQ ) ;
switch( message_ptr->type )
{
case AType:
{
struct A* = (struct A*)message_ptr ;
uint32_t payload = message_ptr->payload ;
...
deallocateMessageA( message_ptr ) ;
}
break;
case BType:
{
struct B* = (struct B*)message_ptr ;
uint8_t payload = message_ptr->payload ;
...
deallocateMessageB( message_ptr ) ;
}
}
我尚未定义的分配/取消分配功能的详细信息。一种简单的方法是使用固定块内存池。如果您的RTOS不提供这些,一种简单的实现是在池中有指向消息的指针队列,每种消息类型一个队列/池。要进行分配,只需将消息从队列中取出来从相关消息池中获取指针,然后通过将指针返回到队列来进行分配。
请注意,某些RTOS允许直接发送可变长度的消息-例如,在embOS中,您可以为队列分配内存池,并在发送而不是在创建队列时指定长度。但是,接收者必须能够接收最大可能的消息。