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

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

[复制链接]
wdzfd 发布时间:2018-12-6 19:56
《RT-Thread内核实现与应用开发实战指南》读书感悟之线程调度
: h' x# M9 i/ f# L  {
) ?$ q; e2 O& y7 n! B2 y7 O* K    首先感谢野火电子和ST社区搞得活动,有幸获得一本赠送的书籍,学习了一段时间先讲下总体感受:全书从初学者入门的角度出发, 第一部分“从0到1教你写RT-Thread内核”重点讲解RT-Thread的原理实现,其中第四章介绍了用MDK5软件仿真工程的建立我认为比较实用,提供了用软件仿真就可以学习RT-Thread内核的方法具有普遍适用性,不再限制于要有硬件才能学习;其中第八章《对象容器的实现》之前在学习其它RTOS知识时了解不多, 通过学习了解到容器是存放各种对象供finsh组件使用,finsh组件是RT-thread操作系统特有的,可惜全书没有进一步讲解finsh的使用,希望后面改版能补充该部分内容(注:rtthread_manual.zh.pdf第十二章有介绍fish shell,想了解的网友可以先进行学习)。第二部分是讲RT-Thread 内核应用开发,讲解了系统移植、启动流程和各操作系统对象的接口使用,按先讲原理概念,再具体接口分析讲解,最后实验验证的顺序,我觉的这样安排很好,非常适合初学者学习。
; b% F- ?6 @2 m) p5 S      然后进入正题分享下线程调度的学习感悟。线程的管理和调度是一个RTOS最基本最核心的功能, RT-Thread相比国内最流行的UCOS-II系统增加了时间片的轮询功能,主要参考书籍的第六、十、十二、十四、十七章内容我们来了解下线程调度的实现特点。, A2 w" \6 f# r6 y
$ z9 E( m8 B/ A
1. 已就绪线程最高优先级的查找, 由两个在scheduler.c文件定义的全局变量进行查找,一个是线程就绪优先级组rt_thread_ready_priority_group,另一个是线程优先级表rt_thread_priority_table[RT_THREAD_PRIORITY_MAX],
3 W9 L) F" y$ t) O  E8 z& B具体代码如下:; Y" \7 U) z" Z' l) A- `7 P
#if RT_THREAD_PRIORITY_MAX <= 32
' x0 I+ X( R5 L# X/ _( {& l8 A: j        highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;( i" Z8 @2 A* a9 R5 c
#else
# N$ O3 ~, Q, U3 ~; h        register rt_ubase_t number;  L2 M) w6 M5 E0 w. Z; Z+ w
        number = __rt_ffs(rt_thread_ready_priority_group) - 1;* B9 N% S, ~1 |
        highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;" _8 @! B- ]- o3 p) Y% E6 g1 e  @! ^
#endif! w2 ?' S- h. T2 ^3 {9 G2 x
这里__rt_ffs函数在低层实现从一个32位的数中寻找从低位开始第一个被置1的位,要根据CPU类型来修改, 书籍第96页有介绍其通用实现方法,我查了mdk5的RRT软件包是直接通过arm cortex-m处理器的CLZ指令得到。
5 s" r' V+ ^, ?6 E4 a线程优先级最多256个是用一个字节表示,当优先级>32时, 高5比特决定rt_thread_ready_priority_group哪个位置位,低3比特决定 rt_thread_ready_table[thread->number]哪个位置位,% b1 e; I7 b4 y1 A* O0 F7 B' Q
所以最终优先级计算公式为:
* l, ?9 C; i" j* Q9 Z    number = __rt_ffs(rt_thread_ready_priority_group) - 1;: R  k& v7 @+ d9 ?2 ~; j7 a
    highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
* s: V$ I8 W  t0 M$ q" e' D1 y可以参考下面线程创建时的代码就清楚了:  a3 C/ Q9 J# L9 j
#if RT_THREAD_PRIORITY_MAX > 32
5 |/ V4 f! N$ w) v            thread->number      = thread->current_priority >> 3;            /* 5bit */# |) i  m& m) y6 o+ }- |
            thread->number_mask = 1 << thread->number;
: w) H( O8 {9 L7 X            thread->high_mask   = 1 << (thread->current_priority & 0x07);   /* 3bit */7 \) a+ Z" s7 t6 b- P1 q
#else' }$ n6 M+ X9 @; U* z, B
            thread->number_mask = 1 << thread->current_priority;
2 H, q1 @: l; o! o# M) f& c#endif
' F& W9 C; b+ C#if RT_THREAD_PRIORITY_MAX > 32
, h) c; @& F4 N0 q8 g+ q9 B" ^    rt_thread_ready_table[thread->number] |= thread->high_mask;
( l- z" m/ r' H$ o( K% z#endif% M9 U1 ?+ s4 h% c- b8 ^
    rt_thread_ready_priority_group |= thread->number_mask;/ ~9 q$ v" |6 c; m$ g
一般来说32个优先级差不多够用, 代码效率也更高些,这也是RT-thread操作系统配置文件的默认值。+ U6 K: a5 ~/ ?: T5 U+ U/ u7 w" x4 e! Z/ W

9 }. N" q. Z- p4 ]+ a2. 时间片的轮询, RT-thread操作系统的线程优先级表的数据类型为rt_list,每个索引号对应线程的优先级,该索引下维护着一条双向链表,当线程就绪时,线程就会根据优先级插入到对应索引的链表,同一个优先级的线程都会被插入到同一条链表中。书籍第二十章有介绍双向链表的概念。线程创建时会把优先级和时间片等数据保存到线程的控制块,线程运行时会自减remaining_tick,代码在Clock.c中的void rt_tick_increase(void)函数,如下所示:& n1 m# M% P5 s3 }
void rt_tick_increase(void). _  s- X7 A( Q# o
{2 V  ]) B- c2 m) H! s1 R
    struct rt_thread *thread;9 _" d- ~& z& x$ W7 f2 I8 O
    /* increase the global tick */; ]3 s! ]0 I: Z# U/ }  O% K
    ++ rt_tick;
$ w$ {8 V, s. {3 e' Z    /* check time slice */
: Q+ l# P$ [) ~! K6 k  ^    thread = rt_thread_self();
- p: H6 v% B  e2 c2 v    -- thread->remaining_tick;( a7 c7 v( `" |3 L8 }( U2 N, S
    if (thread->remaining_tick == 0)0 ?* l: C$ C% z2 V! {0 ~5 l
    {2 I& @2 q6 h0 ]: F/ V
        /* change to initialized tick */
- N" m3 i3 ^2 O; _3 R        thread->remaining_tick = thread->init_tick;/ o3 h2 V6 A; r  w- X- D6 z
        /* yield */7 W- ?2 }  a  K
        rt_thread_yield();! _" @8 V+ B5 c2 M/ j0 T8 F
    }
, z5 l) _6 f1 E; J    /* check timer */
/ H- t& M- P# b" s' o3 I1 O# C    rt_timer_check();8 O" M5 P, x, e' v8 e0 y# f5 A/ p
}' [0 h( e$ e1 h3 W' {
时间片耗完的线程会从就绪列表移除,然后将时间片耗完的线程插入到该优先级下的链表的尾部,把机会让给下一个线程,从这个机制来看同一优先级的线程不能太多,否则线程间的轮询对系统的实时性会有些影响。
  Y% Q6 \. {9 R- N3 z( Y3 C2 M5 |. h7 L, z

评分

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

查看全部评分

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

举报

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