你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

《RT-Thread内核实现与应用开发实战指南》读书感悟之线程...

[复制链接]
wdzfd 发布时间:2018-12-6 19:56
《RT-Thread内核实现与应用开发实战指南》读书感悟之线程调度8 R5 t2 ~$ n4 \0 m2 n! G% q
7 P( a/ I: [4 `' i9 b
    首先感谢野火电子和ST社区搞得活动,有幸获得一本赠送的书籍,学习了一段时间先讲下总体感受:全书从初学者入门的角度出发, 第一部分“从0到1教你写RT-Thread内核”重点讲解RT-Thread的原理实现,其中第四章介绍了用MDK5软件仿真工程的建立我认为比较实用,提供了用软件仿真就可以学习RT-Thread内核的方法具有普遍适用性,不再限制于要有硬件才能学习;其中第八章《对象容器的实现》之前在学习其它RTOS知识时了解不多, 通过学习了解到容器是存放各种对象供finsh组件使用,finsh组件是RT-thread操作系统特有的,可惜全书没有进一步讲解finsh的使用,希望后面改版能补充该部分内容(注:rtthread_manual.zh.pdf第十二章有介绍fish shell,想了解的网友可以先进行学习)。第二部分是讲RT-Thread 内核应用开发,讲解了系统移植、启动流程和各操作系统对象的接口使用,按先讲原理概念,再具体接口分析讲解,最后实验验证的顺序,我觉的这样安排很好,非常适合初学者学习。# @3 T' j# i5 ?+ c% h! S' y
      然后进入正题分享下线程调度的学习感悟。线程的管理和调度是一个RTOS最基本最核心的功能, RT-Thread相比国内最流行的UCOS-II系统增加了时间片的轮询功能,主要参考书籍的第六、十、十二、十四、十七章内容我们来了解下线程调度的实现特点。
# e8 q) ~6 q% h% O8 }& O, l" X& l7 {6 Q  P2 b; V8 F
1. 已就绪线程最高优先级的查找, 由两个在scheduler.c文件定义的全局变量进行查找,一个是线程就绪优先级组rt_thread_ready_priority_group,另一个是线程优先级表rt_thread_priority_table[RT_THREAD_PRIORITY_MAX],
4 d  r' W( E" a  D% x具体代码如下:
" r" g, T1 u+ \#if RT_THREAD_PRIORITY_MAX <= 32) Z% V, W0 @3 Y& l7 M# b
        highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;+ V$ K/ {4 G6 i' G
#else
) H1 K6 v1 B! g        register rt_ubase_t number;: c( E" \5 y4 Q/ d$ w4 N* s, m
        number = __rt_ffs(rt_thread_ready_priority_group) - 1;
2 |; Z' G3 i! I2 E5 w* h2 d        highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;4 O0 N0 e/ |8 {# Q6 k) n. X
#endif  z- N" R6 F$ T( F1 o& i0 ~
这里__rt_ffs函数在低层实现从一个32位的数中寻找从低位开始第一个被置1的位,要根据CPU类型来修改, 书籍第96页有介绍其通用实现方法,我查了mdk5的RRT软件包是直接通过arm cortex-m处理器的CLZ指令得到。& d; E, a! @( v
线程优先级最多256个是用一个字节表示,当优先级>32时, 高5比特决定rt_thread_ready_priority_group哪个位置位,低3比特决定 rt_thread_ready_table[thread->number]哪个位置位,
& v' N# _: U4 L7 ^( d* ~/ }4 [6 N所以最终优先级计算公式为:. v! Y, r4 Z' \6 [5 _  S9 n) a3 V
    number = __rt_ffs(rt_thread_ready_priority_group) - 1;
1 s: \# i& X& ]- h$ a% m    highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;! B0 _7 y$ z" t: q9 h
可以参考下面线程创建时的代码就清楚了:+ V2 S$ |! S) S2 w8 D) M
#if RT_THREAD_PRIORITY_MAX > 32
! m* S7 ~3 e9 Y& o: d            thread->number      = thread->current_priority >> 3;            /* 5bit */
8 ^' H% v3 J8 R, B9 K$ y# F            thread->number_mask = 1 << thread->number;, W: @6 }' T/ L; }5 }0 q! c
            thread->high_mask   = 1 << (thread->current_priority & 0x07);   /* 3bit */
! h: k) \! D" w% h( R#else& l4 ~% ?6 ]  }2 e4 [9 Y
            thread->number_mask = 1 << thread->current_priority;
; V% e( \: q9 S' o#endif
2 w" O4 K& F% K- h( J1 j6 n  S#if RT_THREAD_PRIORITY_MAX > 32; u+ u5 d! f6 o4 D+ ~9 l
    rt_thread_ready_table[thread->number] |= thread->high_mask;! v- T/ k  O- {
#endif
. e" J8 O/ R+ Y, d# g    rt_thread_ready_priority_group |= thread->number_mask;9 p3 s8 Q5 g5 e$ E
一般来说32个优先级差不多够用, 代码效率也更高些,这也是RT-thread操作系统配置文件的默认值。
3 J9 m+ b; c5 s; E* I
% L2 o; ~- v7 z; G, l4 Q$ M( W2. 时间片的轮询, RT-thread操作系统的线程优先级表的数据类型为rt_list,每个索引号对应线程的优先级,该索引下维护着一条双向链表,当线程就绪时,线程就会根据优先级插入到对应索引的链表,同一个优先级的线程都会被插入到同一条链表中。书籍第二十章有介绍双向链表的概念。线程创建时会把优先级和时间片等数据保存到线程的控制块,线程运行时会自减remaining_tick,代码在Clock.c中的void rt_tick_increase(void)函数,如下所示:* f9 p/ _( g% r! b2 Z$ O9 }
void rt_tick_increase(void)
7 @: i- g- r/ K4 x( Y2 Y0 w{# i+ ]0 E- J! v' U
    struct rt_thread *thread;
& V2 |7 w5 A' X/ W/ M    /* increase the global tick */* R6 V9 g, g! N- d/ C" P# t" `* k
    ++ rt_tick;" u( P# k" g4 [, X
    /* check time slice */. h+ j: h* s3 U5 M0 U9 y* ]
    thread = rt_thread_self();( p' B$ G" M* X) \) f5 _( q. h4 n
    -- thread->remaining_tick;
7 h, K. T; b2 ]4 E: O    if (thread->remaining_tick == 0)$ B7 |  Y: a3 m6 r: t& E* y
    {" Z- E1 W; A( m$ y, U
        /* change to initialized tick */6 S4 M  o. {& t0 O( ]6 [& B& |
        thread->remaining_tick = thread->init_tick;- a% ~/ A$ A& {& e- v2 H. d
        /* yield */
8 G* {! q2 e" Z9 T; K1 b# g        rt_thread_yield();
+ T5 l2 q$ H! }! @. }3 W    }
# ?0 r- B5 K8 P0 Z" D    /* check timer */
( `9 Q4 g" `3 G2 T/ j$ a  ^. L    rt_timer_check();' |$ h) L( C( K0 P
}
9 ?6 T2 }9 t( W4 @' k时间片耗完的线程会从就绪列表移除,然后将时间片耗完的线程插入到该优先级下的链表的尾部,把机会让给下一个线程,从这个机制来看同一优先级的线程不能太多,否则线程间的轮询对系统的实时性会有些影响。
4 }# Y1 r1 }2 }2 ~3 f# t
! ^& k2 @  k+ Z

评分

参与人数 1 ST金币 +20 收起 理由
STMCU + 20

查看全部评分

赞 收藏 评论0 发布时间:2018-12-6 19:56

举报

0个回答

所属标签

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版