硬汉嵌入式论坛

 找回密码
 立即注册
查看: 4865|回复: 10
收起左侧

[FreeRTOS] FreeRTOS中如何实现同步消息

[复制链接]

1

主题

6

回帖

1

积分

新手上路

积分
1
发表于 2016-10-23 16:00:04 | 显示全部楼层 |阅读模式
请教坛子里的朋友,FreeRTOS里头可以怎么样 基于队列实现  同步消息  ??


原本我们打算利用两个 异步(消息队列本身是异步的) 消息 实现 一个 同步消息。。


比如:
queue1.png



这个逻辑是很简单了,但是当遇到多任务的时候,就会带出来下面的问题:


queue2.png



针对这个问题,我们自己讨论的结果,比较直观的是在一对 Msg / Ack 携带的消息内容里加上  [ 发送Task / 接收Task ] 的唯一 标识, 比如 接收Task的TaskID。

但如果是这样,又会带来一些额外的工作:

1.  每次发送同步消息前,首先要获取发送/接收Task的标识, 这个标识从何而来; (那我们就得需要 整个 管理 Task的 全局的数据结构,目前也还没有实现的思路)

2.  每个Task因为都会创建属于自己的队列,如何获取自身的队列句柄?;(这个如果第一个问题能够解决,在创建task的时候,就可以将该Task的队列句柄一并绑上,但是否还有别的方法可以做到呢?)

因为刚接触FreeRTOS不久,不了解的地方比较多,也不清楚上面描述的是否清晰或者合理,只是现在光看API手册,源码也没很详细的走读,这个问题就是有点棘手。。

坛子的朋友如果有什么想法思路或者经验 还请不吝赐教。。。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107049
QQ
发表于 2016-10-23 16:14:54 | 显示全部楼层
从你的功能要求来看,用事件标志组可以解决,任务A发送完毕消息后,等待事件标志,那个任务接收到了,回发一个事件标志,不同的任务设置不同的事件标志位。
回复

使用道具 举报

1

主题

6

回帖

1

积分

新手上路

积分
1
 楼主| 发表于 2016-10-23 16:43:05 | 显示全部楼层
嗯,刚刚了解了下事件标志组的内容,似乎可以通过封装《 发送队列消息 + 调用事件标志组阻塞  》 实现这个同步消息功能,我再仔细了解下这个功能,非常感谢!~
回复

使用道具 举报

1

主题

6

回帖

1

积分

新手上路

积分
1
 楼主| 发表于 2016-10-25 00:53:42 | 显示全部楼层
非常感谢管理员指教。。今天了解了下事件组的内容并讨论了下,还是会有几个问题。。

1.  通过封装 《消息队列+事件组标志》,是能够满足消息同步的机制的; 但这里的问题在于,同步消息的功能 还需要满足 接收者 将处理结果 返回 给 正在等待阻塞的发送者的。 类似下面2个图:

图1 表明了 Task B 完成处理Msg1后,即通知 Task A  解除阻塞状态;  但如果Task B 在处理完Msg1后,还需要给 Task A 发送应答消息(如图2), 此时就有了问题:

1)Task A正在阻塞状态, 是处理不了Task B 的 Ack 消息的,所以也就获取不到Task B处理消息后的结果(即同步消息功能实现还是有问题)。 并且,此时Task B 还不能设置事件组标志解除Task A的阻塞状态来处理Ack消息,因为多任务的存在,这时并不能保证该Ack消息唯一来自Task B;  

图1 : a1.png

图2:   a2.png

那针对上面这个问题,也是想了两种解决办法:

1, 比较直观的,在消息携带的内容中还是需要带上Task ID之类的标识,这样的话可以允许Task B在发送完Ack消息后立即设置事件组标志,解除Task A阻塞状态,Task A在消息队列中通过判断内容中的Task ID来判断该Ack是否来自Task B;

2, 就是采用类似任务间共享资源的方式,如图3,将处理结果保存在共享对象中,这样就省去了发送Ack消息的环节,Task B将处理结果保存在共享对象后即可以立即解除Task A的阻塞状态, Task A可以直接使用共享对象中的结果;这个时候就有几点还不了解FreeRTOS的地方:

图3:   a3.png
        1)我目前理解的,在FreeRTOS中动态申请内存,即堆内存,是不是可以多任务共享的? 因为malloc时会返回该内存指针, 这样的话,在同步消息接口封装中,我可以先动态申请一块内存,将该内存指针 通过队列消息发给接收Task,接收Task在处理完消息后,可以通过该指针将处理结果写入。理论上,这样就能达到目的?(因为时间关系,这个目前还未做实验,明天做下实验试试)
        2)如果1)中方法错误,FreeRTOS 有没有类似共享内存的机制,因为我查了下资料,包括坛子里的开发教程,似乎并没有相关内容。。考虑到FreeRTOS整个就是单进程的东东,是不是有更加方便的共享机制?(应该不能只是全局变量。。确实现在不太熟悉FreeRTOS)

望坛子中的朋友不吝赐教。。。感谢感谢。。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107049
QQ
发表于 2016-10-25 01:09:45 | 显示全部楼层
看了你的图1和图2,这个也简单,不需要多余的返回Ack结果,你仅需设置不同事件标志就可以了,不同的标志代表不同的结果,而且还能区分来自那个任务。已经替代Ask功能了。

没有看你的解决方案。
回复

使用道具 举报

1

主题

6

回帖

1

积分

新手上路

积分
1
 楼主| 发表于 2016-10-25 08:52:16 | 显示全部楼层

回 eric2013 的帖子

eric2013:看了你的图1和图2,这个也简单,不需要多余的返回Ack结果,你仅需设置不同事件标志就可以了,不同的标志代表不同的结果,而且还能区分来自那个任务。已经替代Ask功能了。

没有看你的解决方案。
 (2016-10-25 01:09) 
了解,文字性的东西看着比较吃力。。

嗯,返回处理结果的问题通过设置不同事件标志是可以做到的。不过还有2个问题:

1.  如果是Task A 向 Task B 发同步消息 请求 数据 呢?? 这个设置事件标志就做不到了吧(应该没理解错您的意思了);

2.  如果需要解决1的问题,是不是可以通过共享对象的方式? 这种共享对象 可不可以通过发送 Task A 发送 malloc申请的内存指针 给 Task B,由Task B 写入数据实现?? 或者别的共享方式?

多谢!~
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107049
QQ
发表于 2016-10-25 10:03:34 | 显示全部楼层

回 fun0201 的帖子

fun0201:了解,文字性的东西看着比较吃力。。

嗯,返回处理结果的问题通过设置不同事件标志是可以做到的。不过还有2个问题:

....... (2016-10-25 08:52) 
如果还要请求数据的话,整体上就不使用消息队列+事件标志组了,
使用消息队列替换事件标志组,也即是再做一个消息队列。用消息队列做ask,也做数据返回。
回复

使用道具 举报

1

主题

6

回帖

1

积分

新手上路

积分
1
 楼主| 发表于 2016-10-25 11:44:21 | 显示全部楼层

回 eric2013 的帖子

eric2013:如果还要请求数据的话,整体上就不使用消息队列+事件标志组了,
使用消息队列替换事件标志组,也即是再做一个消息队列。用消息队列做ask,也做数据返回。
 (2016-10-25 10:03) 
1. 这个就不太理解了。。 封装《Queue_A(发送消息) + Queue_B(接收消息)》?? 还是别的什么。。
这样在多任务的情况下,Task A中Queue_B里的Ack消息是不能确保唯一来自 Task B的,这样就回到了我最开始疑惑的多任务消息同步问题

2. 已经试验了共享动态内存指针的方式,验证可行,但是否有内存管理方面的风险??请指教下。。

封装代码大致如下:

// 发送同步消息,请求数据
sync_send(..., ackbuf)
{
    // 申请动态内存,用于获取Ack数据
    pTemp = malloc();
   
    // 发送队列消息
    xQueueSend(QHandle, &pTemp, Tick);

    // 阻塞
    xTaskNotifyWait();

    // 拷贝Ack数据并释放动态内存
    copy(ackbuf, pTemp, len);   
    free(pTemp);
}

// 接收同步消息
sync_recv(..., ackbuf)
{
    // 接收队列消息
    xQueueReceive(QHandle, &RecvData, Tick);

    // 填写Ack数据
    pTemp = (AckType *)RecvData;
    pTemp = ......
   
    // 解除Task A阻塞状态
    xTaskNotify()     
}
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107049
QQ
发表于 2016-10-25 12:00:59 | 显示全部楼层

回 fun0201 的帖子

fun0201:1. 这个就不太理解了。。 封装《Queue_A(发送消息) + Queue_B(接收消息)》?? 还是别的什么。。
这样在多任务的情况下,Task A中Queue_B里的Ack消息是不能确保唯一来自 Task B的,这样就回到了我最开始疑惑的多任务消息同步问题

2. 已经试验了共享动态内存指针的方式,验证 .. (2016-10-25 11:44) 
1. 没问题的,你要明白一点,你的任务TaskA往消息队列里面存入数据后,只有一个任务可以从这个消息队列里面获取此数据,其它任务获取消息队列已经没有这个数据了。你的这个任务再返回数据也好,ask应答也好,都可以再次往新创建的消息队列里面放数据,不知道是来自哪个任务的,就再做一个标识符,跟事件标志组一个道理。

2. 没看
-----------------------------------------
回复

使用道具 举报

1

主题

6

回帖

1

积分

新手上路

积分
1
 楼主| 发表于 2016-10-26 00:25:44 | 显示全部楼层

回 eric2013 的帖子

eric2013:1. 没问题的,你要明白一点,你的任务TaskA往消息队列里面存入数据后,只有一个任务可以从这个消息队列里面获取此数据,其它任务获取消息队列已经没有这个数据了。你的这个任务再返回数据也好,ask应答也好,都可以再次往新创建的消息队列里面放数据,不知道是来自哪个任务的,就 .. (2016-10-25 12:00) 
其实这段话我还是有疑义,不太理解的...FreeRTOS里面的内容还需要加深了解。

不过,目前已经有实现这个同步消息功能的思路了,十分感谢。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107049
QQ
发表于 2016-10-26 00:29:53 | 显示全部楼层

回 fun0201 的帖子

fun0201:其实这段话我还是有疑义,不太理解的...FreeRTOS里面的内容还需要加深了解。

不过,目前已经有实现这个同步消息功能的思路了,十分感谢。

....... (2016-10-26 00:25) 
好的,有什么问题了,我们再继续交流。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-15 22:14 , Processed in 0.252031 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表