Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
bug
IPC
RT-Thread一般讨论
rt-thread 系统优化系列(四) 之 再谈 ipc 中的 bug
发布于 2021-09-12 10:17:44 浏览:2572
订阅该版
[tocm] ## 前言 先说一下背景,ipc 里有如下几种同步通信机制:信号量、互斥锁、事件集、邮箱、消息队列。 其中有如下几个 api 有等待超时的能力。 `rt_sem_take` `rt_mutex_take` `rt_event_recv` `rt_mb_send_wait` `rt_mb_recv` `rt_mq_send_wait` `rt_mq_recv` 超时时间可以设置成:0 不等待;-1 永久等;n 等待指定 tick 数。不等待的情况不涉及今天讲的话题。 不同的是前三个和后四个实现上理念有些不同。前三个存在以下隐患。 **但凡设置了等待时间,可能出现未达到超时时间却提前退出等待,让等待资源者错以为获取到了资源使用权!** ### 消息队列的等待逻辑 以 `rt_mq_recv` 为例,从 `rt_mq_recv` 函数可以看出来,当前线程被唤醒后从 `rt_schedule` 返回。接下来判断是否是 error 唤醒,如果是,退出 `rt_mq_recv` ,告诉等待资源者是有 error 退出的;如果不是,下面计算等待时间还剩多少,保证等待满指定的等待时间。 > 注:鉴于目前线程的 error 还不是很完善,ipc 中返回的 error 可以认为是超时错误。下同。 ### 信号量的等待逻辑 以 `rt_sem_take` 为例,当前线程被唤醒后从 `rt_schedule` 返回,只判断了一个线程状态是否有 error,有 error 返回 error;没有 error 返回 RT_EOK!它根本不管线程是怎么被唤醒的。 设想一种情景,一个线程在等待信号量时,有另一个线程 `rt_thread_resume` 想唤醒它。 ### 验证 验证代码很简单,如下: ``` static void rt_thread1_entry(void *parameter) { static rt_uint8_t count = 0; while(1) { rt_thread_mdelay(1000); rt_sem_release(dynamic_sem); } } static void rt_thread2_entry(void *parameter) { static rt_err_t result; while(1) { /* 永久方式等待信号量 */ result = rt_sem_take(dynamic_sem, RT_WAITING_FOREVER); if (result != RT_EOK) { rt_kprintf("t2 take a dynamic semaphore, failed.\n"); } else { rt_kprintf("t2 take a dynamic semaphore, ok.\n); } } } static void rt_thread3_entry(void *parameter) { static rt_err_t result; while(1) { rt_thread_mdelay(100); rt_thread_resume(t2); } } ``` 线程 1 间隔 1s 释放一个资源。线程 2 永久等待资源。而线程 3 模拟意外的线程唤醒,间隔时间是 100ms,便于发现问题。 你会发现,线程 2 获取的资源数比 线程 1 释放的要多。 ### 修改后的 rt_sem_take ``` /* no waiting, return with timeout */ if (sem->value == 0 && timeout == 0) { rt_hw_interrupt_enable(level); return -RT_EFULL; } while (sem->value == 0) { /* current context checking */ RT_DEBUG_IN_THREAD_CONTEXT; /* semaphore is unavailable, push to suspend list */ RT_DEBUG_LOG(RT_DEBUG_IPC, ("sem take: suspend thread - %s\n", thread->name)); /* suspend thread */ _ipc_list_suspend(&(sem->parent.suspend_thread), thread, sem->parent.parent.flag); /* enable interrupt */ rt_hw_interrupt_enable(level); /* has waiting time, start thread timer */ if (timeout > 0) { RT_DEBUG_LOG(RT_DEBUG_IPC, ("set thread:%s to timer list\n", thread->name)); tick_delta = rt_tick_get(); /* reset thread error number */ thread->error = RT_EOK; /* reset the timeout of thread timer and start it */ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &timeout); rt_timer_start(&(thread->thread_timer)); } /* do schedule */ rt_schedule(); if (thread->error != RT_EOK) { /* return error */ return thread->error; } if (timeout > 0) { tick_delta = rt_tick_get() - tick_delta; timeout -= tick_delta; if (timeout < 0) timeout = 0; /* no waiting, return with timeout */ if (timeout == 0) { /* set error as timeout */ thread->error = -RT_ETIMEOUT; /* enable interrupt */ // rt_hw_interrupt_enable(level); return -RT_ETIMEOUT; } } level = rt_hw_interrupt_disable(); } if (sem->value > 0) { /* semaphore is available */ sem->value --; } ``` ## 结尾 其它两个的修改思路可类比,再用上面的测试代码考验,获得资源与释放资源是真同步的了。 > 本系列提到的所有代码更改已经提交到 gitee ,欢迎大家测试 https://gitee.com/thewon/rt_thread_repo 相关文章: [rt-thread 系统优化系列(一) 之 关中断](https://club.rt-thread.org/ask/article/2931.html) [rt-thread 系统优化系列(二) 之 线程间同步和通信对中断的影响](https://club.rt-thread.org/ask/article/2939.html) [rt-thread 系统优化系列(三) 之 软定时器](https://club.rt-thread.org/ask/article/2967.html) [ rt-thread 系统优化系列(四) 之 再谈 ipc 中的 bug](https://club.rt-thread.org/ask/article/3044.html) [rt-thread 系统优化系列(五) 之 线程销毁谜题](https://club.rt-thread.org/ask/article/3138.html) [rt-thread 系统优化系列(六) 之 让 idle 线程闲下来](https://club.rt-thread.org/ask/article/3141.html)
6
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
出出啊
恃人不如自恃,人之为己者不如己之自为也
文章
43
回答
1519
被采纳
343
关注TA
发私信
相关文章
1
有关动态模块加载的一篇论文
2
最近的调程序总结
3
晕掉了,这么久都不见layer2的踪影啊
4
继续K9ii的历程
5
[GUI相关] FreeType 2
6
[GUI相关]嵌入式系统中文输入法的设计
7
20081101 RT-Thread开发者聚会总结
8
嵌入式系统基础
9
linux2.4.19在at91rm9200 上的寄存器设置
10
[转]基于嵌入式Linux的通用触摸屏校准程序
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
DMA
USB
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
I2C_IIC
ESP8266
UART
WIZnet_W5500
ota在线升级
cubemx
PWM
BSP
flash
freemodbus
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
keil_MDK
ulog
SFUD
msh
C++_cpp
MicroPython
本月问答贡献
三世执戟
7
个答案
1
次被采纳
KunYi
5
个答案
1
次被采纳
RTT_逍遥
4
个答案
1
次被采纳
xiaorui
1
个答案
1
次被采纳
JonasWen
1
个答案
1
次被采纳
本月文章贡献
出出啊
1
篇文章
3
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
3
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部