我在运行的一些任务中遇到了一些问题。我有三个任务,其中一个是LCD更新任务,另外两个是电机驱动器任务。我还有两个 ISR 向两个电机驱动器任务发布消息。就安全地传递指针而言,我正在考虑创建一个结构:
typedef struct message{
enum BUTTON_1 = 0, BUTTON_2 = 1, NO_BUTTON = 3; //button ISR to increase motor drive
int timestamp; //A timestamp for the RPM of the motors
}
现在共享内存的问题出现了,所以我在想:
struct message* update_msg = (struct message*)malloc(sizeof(struct message)); //from here I dont know how to creat an object that fills the space allocated.
然后,我将通过队列发送指向结构的指针:
OSTASKQPOST((void *)(st_size)
....
)
在最后一个任务收到消息并对成员变量执行所需的操作后,我将不得不释放内存。
free(st_size)
这样的事情是合理的吗?
这是在线程之间传输数据的"线程间通信 101"方法。 它会正常工作。 假设队列宽为 32 位,随着消息大小的增加,发布结构地址或对象实例开始很快获胜(而不是直接按值发布数据)。
还有其他机制。 在我的 ARM 嵌入式项目中,RAM 有限且内存空间比速度更重要,我倾向于使用 255 个全局消息实例的数组作为池(为"无效索引"保留一个值(例如 255 个)很有用)。 这意味着每条消息只能引用一个字节,并且每条消息中的两个字节允许它们链接到列表和列表之外。 链接列表头字节、互斥锁和信号量构成了线程间通信的阻塞队列 - 不需要额外的存储空间。 所有消息在启动时都链接到"池"队列中,并在线程之间弹出、排队,并由应用线程释放回池中。
从硬件接收数据的 ISR 无法调用 malloc、获取互斥体或等待信号量以获取消息索引。 我使用另一个没有锁的队列类,只有一个字节索引的循环队列。 我在启动时推送了一些消息。 中断处理程序可以将来自此"ISRpool"的消息取消排队,从硬件填充它们,设置一个int(位域!)来识别ISR,将消息索引推送到"ISRout"循环队列中,发出信号信号并通过操作系统退出。 在信号量上等待的线程唤醒并知道 ISRout 上有数据,将其弹出并将其排队到处理来自该 ISR 的消息的任何线程。该"ISRhandler"线程还负责用消息"填充"ISR池,以便ISR在数据到达时始终准备好消息。 这个简单的共享"ISRpool"系统仅在中断不重新启用更高优先级的中断时才有效!
以类似的方式,tx ISR 的消息被推送到循环队列中,以便 ISR 拾取(中断被短暂禁用以查看硬件是否空闲,并且硬件 FIFO 需要"启动"才能再次启动 tx 中断)。 "使用过的"tx 消息被转储到 rx ISRpool 上 - 它们也可以重新用于输入。
池化方案有一些并不明显的优点。 一个是"没有恶意,没有自由"。 消息当然可能会泄露,但我很快注意到 - 我的"监视器/调试器"运行的 UART 的终端提示符是"223>"数字是池级别。 如果这个数字下降并且不再回来,我知道我已经泄露了。 当您不能只在瓦尔格林德:)下运行应用程序时,这一点非常重要