Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RT-Thread一般讨论
一点小总结
发布于 2013-07-15 01:40:26 浏览:5419
订阅该版
下面是一些我犯过的错误,总结了一下,希望能帮到一些对操作系统不太熟悉的新手朋友, 同时也请高手证实一下。 (1)、线程的删除后,要会在rt_thread_delay()放弃CPU主动权后执行idle线程时才会被彻底回收。 若不放弃,则idle线程会一直得不到cpu而无法彻底回收被删除的线程。 [viewtopic.php?f=2&t=2909](http://www.rt-thread.org/phpBB3/viewtopic.php?f=2&t=2909) (2)、若线程出现-2的错误,则很有可能是高优先级的线程一直占用CPU没有释放导致该线程不会被执行。 这是我多次观察的结果,求证。。。 以上两点说明,不要写一直占用CPU的线程,否则IDLE线程一直不会执行,因为IDLE线程的优先级很低。 (3)、软件定时器停止rt_timer_stop后再启动rt_timer_start时,会重新装入初值而重新启动。 (4)、再启动一个已经启动的软件定时器,则会无任何作用,不会对定时器作任何改变。 (5)、sem不具有优先级继承,可能发生优先级反转,可能出现死锁。下面是两个信号量的死锁例子: ``` rt_sem_t sem1,sem2; static void task1_entry(void* para) { rt_kprintf("task1 try to get sem1... "); rt_sem_take(sem1, RT_WAITING_FOREVER); rt_kprintf("task1 got sem1. "); rt_thread_delay(RT_TICK_PER_SECOND); rt_kprintf("task1 try to get sem2... "); rt_sem_take(sem2, RT_WAITING_FOREVER); rt_kprintf("task1 got sem2. "); rt_kprintf("task1 release sem1 "); rt_sem_release(sem1); rt_kprintf("task1 release sem2 "); rt_sem_release(sem2); } static void task2_entry(void* para) { rt_kprintf("task2 try to get sem2... "); rt_sem_take(sem2, RT_WAITING_FOREVER); rt_kprintf("task2 got sem2. "); rt_thread_delay(RT_TICK_PER_SECOND); rt_kprintf("task2 try to get sem1... "); rt_sem_take(sem2, RT_WAITING_FOREVER); rt_kprintf("task2 got sem1. "); rt_kprintf("task2 release sem2 "); rt_sem_release(sem2); rt_kprintf("task2 release sem1 "); rt_sem_release(sem1); } static void test_thread_entry(void* parameter) { rt_thread_t tid; sem1 = rt_sem_create("sem1", 1, RT_IPC_FLAG_PRIO); if (sem1 == RT_NULL) { rt_kprintf("creat sem1 failed. "); return; } sem2 = rt_sem_create("sem2", 1, RT_IPC_FLAG_PRIO); if (sem2 == RT_NULL) { rt_kprintf("creat sem2 failed. "); return; } tid = rt_thread_create("task1",task1_entry,(void *)1,512,20,5); if(tid != RT_NULL) rt_thread_startup(tid); else rt_kprintf("creat task1 failed. "); tid = rt_thread_create("task2",task2_entry,(void *)2,512,20,5); if(tid != RT_NULL) rt_thread_startup(tid); else rt_kprintf("creat task2 failed. "); } ``` 测试结果如下: ``` task1 try to get sem1... task1 got sem1. task2 try to get sem2... task2 got sem2. task1 try to get sem2... task2 try to get sem1... finsh>>list_sem() semaphore v suspend thread -------- --- -------------- sem2 000 1:task1 sem1 000 1:task2 sem1 000 0 shrx 000 0 e0 000 0 tx_wait 000 0 heap 001 0 0, 0x00000000 ``` (6)、信号量的rt_sem_take不能在中断里进行,因为这个函数可能挂起当前线程,而中断里不存在线程一说。 (7)、信号量的释放rt_sem_release可以在中断里进行。 (8)、邮箱、消息队列同(6)、(7)描述相似。 (9)、互斥量不仅仅是二值信号量,它还有所有者,它可以改变当前线程的优先级,当它成功rt_take_mutex时, 它的线程优先级会继承,不会产生优先级翻转。 [viewtopic.php?f=28&t=1974](http://www.rt-thread.org/phpBB3/viewtopic.php?f=28&t=1974) (10)、当互斥量成功rt_take_mutex时,若此线程接着再对这个互斥量rt_take_mutex,也会成功而不会被挂起, 而信号量sem就不一定。 (11)、互斥量的take与release都不能在中断里进行,而信号量的release可以。 (12)、父线程创建子线程时,子线程的优先级不要比父线程的优先级高,在创建多个高优先子线程时,父线程会未完成 我们期望的工作而被抢占,达不到预计目的。例如:下面的低优先级的线程1不会被高优先级的线程2抢占: ``` static void task1_entry(void* para) { rt_uint32_t t1_count; for(t1_count = 0; t1_count < 5; t1_count ++) { rt_kprintf("task1 count: %d ", t1_count); } } static void task2_entry(void* para) { rt_uint32_t t2_count = 0; for(t2_count = 0; t2_count < 5; t2_count ++) { rt_kprintf("task2 count: %d ", t2_count); } } static void test_thread_entry(void* parameter) { rt_thread_t tid; tid = rt_thread_create("task1",task1_entry,(void *)1,512,10,5); if(tid != RT_NULL) rt_thread_startup(tid); else rt_kprintf("creat task1 failed. "); tid = rt_thread_create("task2",task2_entry,(void *)2,512,9,5); if(tid != RT_NULL) rt_thread_startup(tid); else rt_kprintf("creat task2 failed. "); } ``` 结果如下: ``` task1 count: 0 task1 count: 1 task1 count: 2 task1 count: 3 task1 count: 4 task2 count: 0 task2 count: 1 task2 count: 2 task2 count: 3 task2 count: 4 ``` 这是为什么呢?这个时候很容易去怀疑RT-Thread有bug。其实问题出在test_thread_entry 这个父线程的优先级太低,task1创建完成后立即启动,task1比test_thread这个父线程优先级 高,于是立即抢占父线程,task2虽然优先级更高,但是它在task1运行结束之前都还没有被创建!! 所以才会出现这样的现象,让人错觉:task1的优先级至少不会比task2低。 将父线程的优先级改成9(与task2相同优先级)后,再看看结果: ``` task2 count: 0 task2 count: 1 task2 count: 2 task2 count: 3 task2 count: 4 task1 count: 0 task1 count: 1 task1 count: 2 task1 count: 3 task1 count: 4 ``` 一切正常! 后面继续学习,继续补充!(出现了问题要多多怀疑自己)
查看更多
17
个回答
默认排序
按发布时间排序
aozima
2013-07-15
调网络不抓包,调I2C等时序不上逻辑分析仪,就像电工不用万用表!多用整理的好的文字,比截图更省流量,还能在整理过程中思考。
楼主总结得真不错。
grissiom
2013-07-15
这家伙很懒,什么也没写!
总结的不错~ 多多总结会有收获的~~ 5,死锁和优先级反转没有关系,mutex 也可以死锁~ LZ 可以继续深究优先级反转是怎么一回事,以及现有的(不只是 RTT 上的)解决方法。 12,如果父线程的最后一个动作是启动子线程,那么是没有关系的。其实,即使是在中间,子线程的优先级也可以比父线程优先级高,这个得看自己需要达到什么样的目的~再其实,RTT 里面的线程是没有父子关系的~
bernard
2013-07-15
这家伙很懒,什么也没写!
能够总结到这些,那么RTOS也基本入门了
nongxiaoming
2013-07-15
rt-thread大师兄
不错,很有参考价值
luoyuncong
2013-07-15
这家伙很懒,什么也没写!
你总结的第(4)点,我也疑惑过,当定时器处于开启状态时,调用start方法是不起任何作用的,这跟我使用的上位机(Qt 5.1)不同,我上位机开发中,调用定时器start时,相当于重新启用定时器的。还好,这不算是问题,明白rtthread的定时器就好了。
celticzy
2013-07-15
这家伙很懒,什么也没写!
>总结的不错~ 多多总结会有收获的~~ > >5,死锁和优先级反转没有关系,mutex 也可以死锁~ LZ 可以继续深究优先级反转是怎么一回事,以及现有的(不只是 RTT 上的)解决方法。 > >12,如果父线程的最后一个动作是启动子线程,那么是没有关系的。其实,即使是在中间,子线程的优先级也可以比父线程优先级高,这个得看自己需要达到什么样的目的~再其实,RTT 里面的线程是没有父子关系的~ --- 5、mutex的死锁那会儿也验证了,优先级反转也测试了几个例子,但还是感觉心里没底,看来只有在实战中多多练练才会有心得。 12、有关系吧?最后一个动作启动子线程,也会先启动一个,后启动另一个,只要一启动子线程,父线程就会被立即抢占(假设我的tick足够小)。另外我还试了试,如果不改优级,关中断也是可以的,不过看着感觉不爽,因为有rt_kprintf,所以就没这样用,我也没有在参编程手册和在线APi文档上没有找到关于禁止调度器的API(子父线程,我是看到操作系统的书上这样称呼,我才这样写的。)
prife
2013-07-15
这家伙很懒,什么也没写!
>>总结的不错~ 多多总结会有收获的~~ >>12、有关系吧?最后一个动作启动子线程,也会先启动一个,后启动另一个,只要一启动父线程就会被立即抢占(假设我的tick足够小)。另外我还试了试,如果不改优级,关中断也是可以的,不过看着感觉不爽,因为有rt_kprintf,所以就没这样用,我也没有在参编程手册和在线APi文档上没有找到关于禁止调度的API(子父线程,我是看到操作系统的书上这样称呼,我才这样写的。) > >--- --- 所谓父子线程,并不是说某个线程中启动了另外一个线程,那么第一个线程就是父线程,其启动的线程就是子线程了。并不是这样简单。具有父子关系的线程里,例如,子线程退出,一般来说,父线程需要负责完成一些子线程退出后的资源回收工作。并且子线程退出,父线程也是可以知道的。如果父线程先于子线程退出,则子线程变成孤儿线程,此时内核一般都会指定init作为其父线程。在RTT里,显然没有这样的关系。是以并不存在父子线程的概念。
celticzy
2013-07-15
这家伙很懒,什么也没写!
>你总结的第(4)点,我也疑惑过,当定时器处于开启状态时,调用start方法是不起任何作用的,这跟我使用的上位机(Qt 5.1)不同,我上位机开发中,调用定时器start时,相当于重新启用定时器的。还好,这不算是问题,明白rtthread的定时器就好了。 --- 嗯,后来我看源码也进一步得到了证明。 同样,stop一个已经停止的定时器也不会有任何作用,不过这是显而易见的,不需要注意。
celticzy
2013-07-15
这家伙很懒,什么也没写!
>所谓父子线程,并不是说某个线程中启动了另外一个线程,那么第一个线程就是父线程,其启动的线程就是子线程了。并不是这样简单。具有父子关系的线程里,例如,子线程退出,一般来说,父线程需要负责完成一些子线程退出后的资源回收工作。并且子线程退出,父线程也是可以知道的。如果父线程先于子线程退出,则子线程变成孤儿线程,此时内核一般都会指定init作为其父线程。在RTT里,显然没有这样的关系。是以并不存在父子线程的概念。 --- 哦,也就是说RTT的线程结构体是没有记录子父线程关系的数据域,也不存在相关的动作方法,这样叫就自然不对了,是吗?
nongxiaoming
2013-07-15
rt-thread大师兄
>你总结的第(4)点,我也疑惑过,当定时器处于开启状态时,调用start方法是不起任何作用的,这跟我使用的上位机(Qt 5.1)不同,我上位机开发中,调用定时器start时,相当于重新启用定时器的。还好,这不算是问题,明白rtthread的定时器就好了。 --- Qt的定时器start()方法是带有重载的,有带参数的重载方法,所有调用start方法会直接去重新跑,而不去判断定时器当前是否在跑,这样可以由用户重新设定定时时间然后启动生效。
撰写答案
登录
注册新账号
关注者
0
被浏览
5.4k
关于作者
celticzy
这家伙很懒,什么也没写!
提问
14
回答
54
被采纳
0
关注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组件
最新文章
1
【NXP-MCXA153】 定时器驱动移植
2
GD32F450 看门狗驱动适配
3
【NXP-MCXA153】看门狗驱动移植
4
RT-Thread Studio V2.2.9 Release Note
5
CherryUSB的bootuf2配置
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
freemodbus
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
keil_MDK
msh
ulog
C++_cpp
MicroPython
本月问答贡献
踩姑娘的小蘑菇
7
个答案
2
次被采纳
a1012112796
18
个答案
1
次被采纳
Ryan_CW
5
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
本月文章贡献
YZRD
3
篇文章
6
次点赞
catcatbing
3
篇文章
6
次点赞
lizimu
2
篇文章
9
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部