diff --git a/rt-thread-version/rt-thread-standard/programming-manual/basic/basic.md b/rt-thread-version/rt-thread-standard/programming-manual/basic/basic.md index 0b0883aee4da91ec0addbb6e495064a6f6987697..0e3d68789b667602ac12594a135e52e593a0b9ab 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/basic/basic.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/basic/basic.md @@ -2,10 +2,9 @@ 本章介绍 RT-Thread 内核基础,包括:内核简介、系统的启动流程及内核配置的部分内容,为后面的章节奠定基础。 -RT-Thread 内核的简单介绍,从软件架构入手讲解实时内核的组成与实现,这部分给初学者引入一些 RT-Thread 内核相关的概念与基础知识,让初学者对内核有初步的了解。学完本章,读者将会对 RT-Thread 内核有基本的了解,知道内核的组成部分、系统如何启动、内存分布情况以及内核配置方法。 +RT-Thread 内核的简单介绍,从软件架构入手讲解实时内核的组成与实现,这部分给初学者引入一些 RT-Thread 内核相关的概念与基础知识,让初学者对内核有初步的了解,知道内核的组成部分、系统如何启动、内存分布情况以及内核配置方法。 -RT-Thread 内核介绍 ------------------ +## RT-Thread 内核介绍 内核是一个操作系统的核心,是操作系统最基础也是最重要的部分。它负责管理系统的线程、线程间通信、系统时钟、中断及内存等。下图为 RT-Thread 内核架构图,可以看到内核处于硬件层之上,内核部分包括内核库、实时内核实现。 @@ -35,13 +34,13 @@ RT-Thread 的时钟管理以时钟节拍为基础,时钟节拍是 RT-Thread ### 线程间同步 -RT-Thread 采用信号量、互斥量与事件集实现线程间同步。线程通过对信号量、互斥量的获取与释放进行同步;互斥量采用优先级继承的方式解决了实时系统常见的优先级翻转问题。线程同步机制支持线程按优先级等待或按先进先出方式获取信号量或互斥量。线程通过对事件的发送与接收进行同步;事件集支持多事件的 “或触发” 和“与触发”,适合于线程等待多个事件的情况。 +RT-Thread 采用信号量、互斥量与事件集实现线程间同步。线程通过对信号量、互斥量的获取与释放进行同步;互斥量采用优先级继承的方式解决了实时系统常见的优先级翻转问题。线程同步机制支持线程按优先级等待方式获取信号量或互斥量。线程通过对事件的发送与接收进行同步;事件集支持多事件的 “或触发” 和“与触发”,适合于线程等待多个事件的情况。 信号量、互斥量与事件集的概念将在[《线程间同步》](../ipc1/ipc1.md)章节详细介绍。 ### 线程间通信 -RT-Thread 支持邮箱和消息队列等通信机制。邮箱中一封邮件的长度固定为 4 字节大小;消息队列能够接收不固定长度的消息,并把消息缓存在自己的内存空间中。邮箱效率较消息队列更为高效。邮箱和消息队列的发送动作可安全用于中断服务例程中。通信机制支持线程按优先级等待或按先进先出方式获取。 +RT-Thread 支持邮箱和消息队列等通信机制。邮箱中一封邮件的长度固定为 4 字节大小;消息队列能够接收不固定长度的消息,并把消息缓存在自己的内存空间中。邮箱效率较消息队列更为高效。邮箱和消息队列的发送动作可安全用于中断服务例程中。通信机制支持线程按优先级等待方式获取。 邮箱和消息队列的概念将在[《线程间通信》](../ipc2/ipc2.md)章节详细介绍。 @@ -62,8 +61,7 @@ RT-Thread 将 PIN、I2C、SPI、USB、UART 等作为外设设备,统一通过 I/O 设备管理的概念将在[《设备模型》](../device/device.md)及[《通用设备》](../device/adc/adc.md)章节展开讲解。 -RT-Thread 启动流程 ------------------- +## RT-Thread 启动流程 一般了解一份代码大多从启动部分开始,同样这里也采用这种方式,先寻找启动的源头。RT-Thread 支持多种平台和多种编译器,而 rtthread_startup() 函数是 RT-Thread 规定的统一启动入口。一般执行顺序是:系统先从启动文件开始运行,然后进入 RT-Thread 的启动函数 rtthread_startup() ,最后进入用户入口函数 main(),如下图所示: @@ -153,9 +151,7 @@ int main(void) } ``` - -RT-Thread 程序内存分布 ---------------------- +## RT-Thread 程序内存分布 一般 MCU 包含的存储空间有:片内 Flash 与片内 RAM,RAM 相当于内存,Flash 相当于硬盘。编译器会将一个程序分类为好几个部分,分别存储在 MCU 不同的存储区。 @@ -179,7 +175,7 @@ Build Time Elapsed: 00:00:07 4)ZI-data:0 数据段,存放未初始化的全局变量及初始化为 0 的变量; -编译完工程会生成一个. map 的文件,该文件说明了各个函数占用的尺寸和地址,在文件的最后几行也说明了上面几个字段的关系: +编译完工程会生成一个`.map` 的文件,该文件说明了各个函数占用的尺寸和地址,在文件的最后几行也说明了上面几个字段的关系: ``` Total RO Size (Code + RO Data) 53668 ( 52.41kB) @@ -228,8 +224,7 @@ void sensor_init() sensor_value 存放在 ZI 段中,系统启动后会自动初始化成零(由用户程序或编译器提供的一些库函数初始化成零)。sensor_inited 变量则存放在 RW 段中,而 sensor_enable 存放在 RO 段中。 -RT-Thread 自动初始化机制 ------------------------ +## RT-Thread 自动初始化机制 自动初始化机制是指初始化函数不需要被显式调用,只需要在函数定义处通过宏定义的方式进行申明,就会在系统启动过程中被执行。 @@ -283,8 +278,7 @@ RT-Thread 的自动初始化机制使用了自定义 RTI 符号段,将需要 初始化函数主动通过这些宏接口进行申明,如 INIT_BOARD_EXPORT(rt_hw_usart_init),链接器会自动收集所有被申明的初始化函数,放到 RTI 符号段中,该符号段位于内存分布的 RO 段中,该 RTI 符号段中的所有函数在系统初始化时会被自动调用。 -RT-Thread 内核对象模型 ---------------------- +## RT-Thread 内核对象模型 ### 静态对象和动态对象 diff --git a/rt-thread-version/rt-thread-standard/programming-manual/interrupt/interrupt.md b/rt-thread-version/rt-thread-standard/programming-manual/interrupt/interrupt.md index ff48063f9d8d51751a4e10c120c9239cb9d426d4..a31f6f44d06d1193ed381b53d077f476fa870f52 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/interrupt/interrupt.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/interrupt/interrupt.md @@ -261,8 +261,7 @@ void demo_nw_isr(int vector, void *param) 从上面例子的两个代码片段可以看出,中断服务程序通过对一个信号量对象的等待和释放,来完成中断 Bottom Half 的起始和终结。由于将中断处理划分为 Top 和 Bottom 两个部分后,使得中断处理过程变为异步过程。这部分系统开销需要用户在使用 RT-Thread 时,必须认真考虑中断服务的处理时间是否大于给 Bottom Half 发送通知并处理的时间。 -RT-Thread 中断管理接口 ---------------------- +## RT-Thread 中断管理接口 为了把操作系统和系统底层的异常、中断硬件隔离开来,RT-Thread 把中断和异常封装为一组抽象接口,如下图所示: @@ -453,8 +452,7 @@ rt_uint8_t rt_interrupt_get_nest(void); | 1 | 当前系统处于中断上下文环境中 | | 大于 1 | 当前中断嵌套层次 | -中断与轮询 ----------- +## 中断与轮询 当驱动外设工作时,其编程模式到底采用中断模式触发还是轮询模式触发往往是驱动开发人员首先要考虑的问题,并且这个问题在实时操作系统与分时操作系统中差异还非常大。因为轮询模式本身采用顺序执行的方式:查询到相应的事件然后进行对应的处理。所以轮询模式从实现上来说,相对简单清晰。例如往串口中写入数据,仅当串口控制器写完一个数据时,程序代码才写入下一个数据(否则这个数据丢弃掉)。相应的代码可以是这样的: @@ -487,8 +485,7 @@ rt_uint8_t rt_interrupt_get_nest(void); 2)必要情况下更改中断模式为轮询模式。同时为了解决轮询方式一直抢占处理机,其他低优先级线程得不到运行的情况,可以把轮询线程的优先级适当降低。 -全局中断开关使用示例 --------------------- +## 全局中断开关使用示例 这是一个中断的应用例程:在多线程访问同一个变量时,使用开关全局中断对该变量进行保护,如下代码所示: @@ -552,7 +549,7 @@ MSH_CMD_EXPORT(interrupt_sample, interrupt sample); 仿真运行结果如下: -``` +```shell \ | / - RT - Thread Operating System / | \ 3.1.0 build Aug 27 2018 diff --git a/rt-thread-version/rt-thread-standard/programming-manual/ipc1/ipc1.md b/rt-thread-version/rt-thread-standard/programming-manual/ipc1/ipc1.md index a761acfd0c389b03ce3dd94f89967a4d655ee0ce..b66f1dcf2d9000ecc9436719f78527608c0e1431 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/ipc1/ipc1.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/ipc1/ipc1.md @@ -473,8 +473,8 @@ MSH_CMD_EXPORT(producer_consumer, producer_consumer sample); 该例程的仿真结果如下: -``` -\ | / +```shell + \ | / - RT - Thread Operating System / | \ 3.1.0 build Aug 27 2018 2006 - 2018 Copyright by rt-thread team @@ -561,8 +561,7 @@ the consumer exit! > [!NOTE] > 注:一般资源计数类型多是混合方式的线程间同步,因为对于单个的资源处理依然存在线程的多重访问,这就需要对一个单独的资源进行访问、处理,并进行锁方式的互斥操作。 -互斥量 ------- +## 互斥量 互斥量又叫相互排斥的信号量,是一种特殊的二值信号量。互斥量类似于只有一个车位的停车场:当有一辆车进入的时候,将停车场大门锁住,其他车辆在外面等候。当里面的车出来时,将停车场大门打开,下一辆车才可以进入。 @@ -826,8 +825,8 @@ MSH_CMD_EXPORT(mutex_sample, mutex sample); 线程 1 与线程 2 中均使用互斥量保护对 2 个 number 的操作(倘若将线程 1 中的获取、释放互斥量语句注释掉,线程 1 将对 number 不再做保护),仿真运行结果如下: -``` -\ | / +```shell + \ | / - RT - Thread Operating System / | \ 3.1.0 build Aug 24 2018 2006 - 2018 Copyright by rt-thread team @@ -976,8 +975,8 @@ MSH_CMD_EXPORT(pri_inversion, prio_inversion sample); 仿真运行结果如下: -``` -\ | / +```shell + \ | / - RT - Thread Operating System / | \ 3.1.0 build Aug 27 2018 2006 - 2018 Copyright by rt-thread team @@ -1002,8 +1001,7 @@ test OK. (2)可能会由于多线程同步而造成优先级翻转的情况。 -事件集 ------- +## 事件集 事件集也是线程间同步的机制之一,一个事件集可以包含多个事件,利用事件集可以完成一对多,多对多的线程间同步。下面以坐公交为例说明事件,在公交站等公交时可能有以下几种情况: diff --git a/rt-thread-version/rt-thread-standard/programming-manual/ipc2/ipc2.md b/rt-thread-version/rt-thread-standard/programming-manual/ipc2/ipc2.md index f53ba5e6ad87b8a72e5d7fe5a48c64cace5ad72c..49868be93783b46e1c4761c7b8005a6e0fac2089 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/ipc2/ipc2.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/ipc2/ipc2.md @@ -378,8 +378,7 @@ if (rt_mb_recv(mb, (rt_uint32_t*)&msg_ptr) == RT_EOK) } ``` -消息队列 --------- +## 消息队列 消息队列是另一种常用的线程间通讯方式,是邮箱的扩展。可以应用在多种场合:线程间的消息交换、使用串口接收不定长数据等。 @@ -836,8 +835,7 @@ struct msg 第一种类型的消息使用了邮箱来作为确认标志,而第二种类型的消息采用了信号量来作为确认标志。邮箱作为确认标志,代表着接收线程能够通知一些状态值给发送线程;而信号量作为确认标志只能够单一的通知发送线程,消息已经确认接收。 -信号 ----- +## 信号 信号(又称为软中断信号),在软件层次上是对中断机制的一种模拟,在原理上,一个线程收到一个信号与处理器收到一个中断请求可以说是类似的。 diff --git a/rt-thread-version/rt-thread-standard/programming-manual/thread/thread.md b/rt-thread-version/rt-thread-standard/programming-manual/thread/thread.md index c1c95d839fe39e482b5e000c32c4f0d27977f746..241d68551be039ebf88b7750c58dc653f5a1bc76 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/thread/thread.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/thread/thread.md @@ -93,7 +93,7 @@ RT-Thread 线程具有独立的栈,当进行线程切换时,会将当前线 线程运行的过程中,同一时间内只允许一个线程在处理器中运行,从运行的过程上划分,线程有多种不同的运行状态,如初始状态、挂起状态、就绪状态等。在 RT-Thread 中,线程包含五种状态,操作系统会自动根据它运行的情况来动态调整它的状态。 RT-Thread 中线程的五种状态,如下表所示: -|**状态**|**描述** | +| 状态 | 描述 | |--------|---------------------------------------------------------------------------------| | 初始状态 | 当线程刚开始创建还没开始运行时就处于初始状态;在初始状态下,线程不参与调度。此状态在 RT-Thread 中的宏定义为 RT_THREAD_INIT | | 就绪状态 | 在就绪状态下,线程按照优先级排队,等待被执行;一旦当前线程运行完毕让出处理器,操作系统会马上寻找最高优先级的就绪态线程运行。此状态在 RT-Thread 中的宏定义为 RT_THREAD_READY | @@ -412,11 +412,9 @@ rt_err_t rt_thread_control(rt_thread_t thread, rt_uint8_t cmd, void* arg); 指示控制命令 cmd 当前支持的命令包括: -•RT_THREAD_CTRL_CHANGE_PRIORITY:动态更改线程的优先级; - -•RT_THREAD_CTRL_STARTUP:开始运行一个线程,等同于 rt_thread_startup() 函数调用; - -•RT_THREAD_CTRL_CLOSE:关闭一个线程,等同于 rt_thread_delete() 或 rt_thread_detach() 函数调用。 +- RT_THREAD_CTRL_CHANGE_PRIORITY:动态更改线程的优先级; +- RT_THREAD_CTRL_STARTUP:开始运行一个线程,等同于 rt_thread_startup() 函数调用; +- RT_THREAD_CTRL_CLOSE:关闭一个线程,等同于 rt_thread_delete() 或 rt_thread_detach() 函数调用。 ### 设置和删除空闲钩子 @@ -558,8 +556,8 @@ MSH_CMD_EXPORT(thread_sample, thread sample); 仿真运行结果如下: -```c -\ | / +```shell + \ | / - RT - Thread Operating System / | \ 3.1.0 build Aug 24 2018 2006 - 2018 Copyright by rt-thread team @@ -743,7 +741,7 @@ MSH_CMD_EXPORT(scheduler_hook, scheduler_hook sample); 仿真运行结果如下: -```c +```shell \ | / - RT - Thread Operating System / | \ 3.1.0 build Aug 27 2018