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

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

[复制链接]
wdzfd 发布时间:2018-12-6 19:56
《RT-Thread内核实现与应用开发实战指南》读书感悟之线程调度
* H9 @# A# O; d9 U  z, F
# R, B$ O* N/ l- Q& L5 o( R    首先感谢野火电子和ST社区搞得活动,有幸获得一本赠送的书籍,学习了一段时间先讲下总体感受:全书从初学者入门的角度出发, 第一部分“从0到1教你写RT-Thread内核”重点讲解RT-Thread的原理实现,其中第四章介绍了用MDK5软件仿真工程的建立我认为比较实用,提供了用软件仿真就可以学习RT-Thread内核的方法具有普遍适用性,不再限制于要有硬件才能学习;其中第八章《对象容器的实现》之前在学习其它RTOS知识时了解不多, 通过学习了解到容器是存放各种对象供finsh组件使用,finsh组件是RT-thread操作系统特有的,可惜全书没有进一步讲解finsh的使用,希望后面改版能补充该部分内容(注:rtthread_manual.zh.pdf第十二章有介绍fish shell,想了解的网友可以先进行学习)。第二部分是讲RT-Thread 内核应用开发,讲解了系统移植、启动流程和各操作系统对象的接口使用,按先讲原理概念,再具体接口分析讲解,最后实验验证的顺序,我觉的这样安排很好,非常适合初学者学习。, Q  }" i8 E' x( t( G( ~0 N9 _
      然后进入正题分享下线程调度的学习感悟。线程的管理和调度是一个RTOS最基本最核心的功能, RT-Thread相比国内最流行的UCOS-II系统增加了时间片的轮询功能,主要参考书籍的第六、十、十二、十四、十七章内容我们来了解下线程调度的实现特点。% k/ T, E6 U6 s/ q. p4 W

7 H' S# p2 }3 u5 U- s1. 已就绪线程最高优先级的查找, 由两个在scheduler.c文件定义的全局变量进行查找,一个是线程就绪优先级组rt_thread_ready_priority_group,另一个是线程优先级表rt_thread_priority_table[RT_THREAD_PRIORITY_MAX], / e: B3 O3 o, L  e2 r
具体代码如下:
/ P! \/ q" y- z, `4 p#if RT_THREAD_PRIORITY_MAX <= 32
* O) ~/ {- v, g6 T( I        highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
/ t- d: t4 D1 ~; q1 a3 v  _#else
. ?5 |$ j, @' V9 v' }6 C        register rt_ubase_t number;
3 E3 O% J8 D2 D5 |( \) I        number = __rt_ffs(rt_thread_ready_priority_group) - 1;1 V$ ^/ V( e% W
        highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;1 O% Y4 t6 z$ |. F' C1 a' _; L
#endif) r" i) F4 b. U7 x4 V$ f
这里__rt_ffs函数在低层实现从一个32位的数中寻找从低位开始第一个被置1的位,要根据CPU类型来修改, 书籍第96页有介绍其通用实现方法,我查了mdk5的RRT软件包是直接通过arm cortex-m处理器的CLZ指令得到。
% u0 F8 a3 K' V5 f' a线程优先级最多256个是用一个字节表示,当优先级>32时, 高5比特决定rt_thread_ready_priority_group哪个位置位,低3比特决定 rt_thread_ready_table[thread->number]哪个位置位,
) i6 F+ c* u+ W* r& z+ A6 R% ~  G所以最终优先级计算公式为:" R- w& T/ o. ]8 d4 ~. t
    number = __rt_ffs(rt_thread_ready_priority_group) - 1;- g$ D5 x2 X! u4 c2 Z, T
    highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;9 e# o5 a2 D( _/ w
可以参考下面线程创建时的代码就清楚了:
% S6 a0 @' d# a2 o$ A0 d) S- z#if RT_THREAD_PRIORITY_MAX > 320 x$ v" C) {8 q8 @7 C# X: g7 g
            thread->number      = thread->current_priority >> 3;            /* 5bit */1 r; a2 i+ b8 j. x$ g  I
            thread->number_mask = 1 << thread->number;) P1 R7 D2 T6 R: O' e
            thread->high_mask   = 1 << (thread->current_priority & 0x07);   /* 3bit */8 ?: A* V7 t2 {( X0 L
#else
& M0 I7 {3 W- ^- X& J  L            thread->number_mask = 1 << thread->current_priority;
/ R" Q/ T4 ^/ I0 V. p  ?- G#endif' x5 \$ F6 |5 J; Y, w7 y% s2 h- J
#if RT_THREAD_PRIORITY_MAX > 32
! K% w( D! a& C0 R% v, d    rt_thread_ready_table[thread->number] |= thread->high_mask;: n) u. Z4 M; k9 A8 s0 m
#endif9 y' g/ y% ~2 ~* X0 W
    rt_thread_ready_priority_group |= thread->number_mask;! V2 d% m2 Q2 `& D( \
一般来说32个优先级差不多够用, 代码效率也更高些,这也是RT-thread操作系统配置文件的默认值。
+ g) L/ f- }0 E$ Z& s6 j
; i* B6 b" I- S- j2. 时间片的轮询, RT-thread操作系统的线程优先级表的数据类型为rt_list,每个索引号对应线程的优先级,该索引下维护着一条双向链表,当线程就绪时,线程就会根据优先级插入到对应索引的链表,同一个优先级的线程都会被插入到同一条链表中。书籍第二十章有介绍双向链表的概念。线程创建时会把优先级和时间片等数据保存到线程的控制块,线程运行时会自减remaining_tick,代码在Clock.c中的void rt_tick_increase(void)函数,如下所示:5 W2 k3 ~. M0 z, j( e, }7 w7 T
void rt_tick_increase(void)
7 ?# Z4 I+ F! O. q/ \{0 o% V6 p( ?% {+ h
    struct rt_thread *thread;4 N8 \! B3 j# _* M; Y5 N4 t
    /* increase the global tick */
7 R- `' o* X% r' Y# j  c    ++ rt_tick;
9 f5 o- {4 S  m. }" O    /* check time slice */
: U8 H1 A5 s  G. v# ^0 N  P    thread = rt_thread_self();
+ }9 v! y# }; T- d$ [( D* s    -- thread->remaining_tick;* Y" ~0 P+ f. y: f
    if (thread->remaining_tick == 0)3 c% C% f: @  l
    {* ^8 q' [' F6 l
        /* change to initialized tick *// m" e, O. x0 P  y
        thread->remaining_tick = thread->init_tick;
3 S# P' ~$ v% {4 c; u4 n% e  Z        /* yield */
/ q2 f8 ~. ^, \& v6 i        rt_thread_yield();
. `1 y% x: l0 k* @5 A% M    }
. }8 L9 T( P. s) L2 H    /* check timer */
& r; {" S5 H& C" i! A    rt_timer_check();
6 H) n3 @9 r) H}) C; e7 I# w0 O5 [
时间片耗完的线程会从就绪列表移除,然后将时间片耗完的线程插入到该优先级下的链表的尾部,把机会让给下一个线程,从这个机制来看同一优先级的线程不能太多,否则线程间的轮询对系统的实时性会有些影响。
2 _, [, h4 r3 V  I$ V
/ U. R3 x9 f( T1 s5 b7 q0 E, Z

评分

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

查看全部评分

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

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版