学习RT-thread(线程、线程调度方式、线程状态)
1. RT-Threaad线程
在日常生活中,我们要完成一个大任务,一般会将它分解成多个简单、容易解决的小问题,小问题逐个 被解决,大问题也就随之解决了。
例如让嵌入式系统执行这样的任务,系统通过传感器采集数据,并通过显示屏将数据显示出来,在多线 程实时系统中,可以将这个任务分解成两个子任务,如下图所示,一个子任务不间断地读取传感器数 据,并将数据写到共享内存中,另外一个子任务周期性的从共享内存中读取数据,并将传感器数据输出 到显示屏上。

在 RT-Thread 中,与上述子任务对应的程序实体就是线程,它是 RT-Thread 中最基本的调度单位,它描 述了一个任务执行的运行环境,也描述了这个任务所处的优先等级,重要的任务可设置相对较高的优先级,非重要的任务可以设置较低的优先级,不同的任务还可以设置相同的优先级,轮流运行。
1.1 线程启动
rt_err_t rt_thread_startup(rt_thread_t thread);
1.2 线程创建和删除线程
1.2.1 创建/删除函数
创建线程函数:
rt_err_t rt_thread_init(struct rt_thread* thread,const char* name,void (*entry)(void* parameter), void* parameter,void* stack_start, rt_uint32_t stack_size,rt_uint8_t priority, rt_uint32_t tick);


删除线程函数
rt_err_t rt_thread_detach (rt_thread_t thread);
2. 线程调度方式
2.1 抢占调度
RT-Thread 的线程调度器是抢占式的,主要的工作就是从就绪线程列表中查找最高优先级线程,保证最 高优先级的线程能够被运行,最高优先级的任务一旦就绪,总能得到CPU的使用权。

总结:
1. 高优先级线程一旦就绪,总能得到CPU的使用权
2. 高优先级线程不阻塞,低优先级线程将无法获得执行权
3. 被抢占的线程将进入就绪态
2.2 时间片轮转
每个线程都有时间片这个参数,但时间片仅对优先级相同的就绪态线程有效。系统对优先级相同的就绪 态线程采用时间片轮转的调度方式进行调度时,时间片起到约束线程单次运行时长的作用,其单位是一 个系统节拍(OS Tick)
假设有 2 个优先级相同的就绪态线程 A 与 B,A 线程的时间片设置为 10,B 线程的时间片设置为 5,那 么当系统中不存在比 A 优先级高的就绪态线程时,系统会在 A、B 线程间来回切换执行,并且每次对 A 线程执行 10 个节拍的时长,对 B 线程执行 5 个节拍的时长,如下图

总结:
1. 同等优先级线程,轮流执行,时间片流转
2. 一个时间片的大小,取决于系统时钟的周期
3. 当前任务的时间片没有使用完,将不会再使用
3. 线程状态
RT-Thread的线程5种状态:
初始状态:线程刚创建所处的状态。
就绪状态:处于就绪状态的线程是指以满足条件运行的线程(没有被阻塞和挂起的任务),但是当 前没有运行的线程,因为同等优先级线程或更高优先级线程正在运行
挂起状态:处于挂起状态的线程是指当前任务因延时,或等待信号量,消息队列,邮箱,互斥量, 事件集等而处于的状态。
运行状态:当前线程处于运行状态,即获得CPU的使用权的线程。
关闭状态:线程被删除后所处状态。

4.线程实操
实验要求:
分别通过创建两个个线程:
线程1:线程间隔50个tick,输出一条打印;
线程2:线程间隔200个tick,输出一条打印;线程创建1000个tick之后,删除线程。
代码实现:
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <rtthread.h>
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
struct rt_thread thread_handle1;struct rt_thread thread_handle2;char thread_stack1[256];char thread_stack2[256];/* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);void thread_test1(void* parameter)
{while(1){rt_kprintf("rice1\r\n");rt_thread_delay(50);}
}void thread_test2(void* parameter)
{while(1){rt_kprintf("rice2\r\n");rt_thread_delay(200);}
}
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @brief The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */rt_thread_init(&thread_handle1,"thread1",thread_test1,NULL,thread_stack1,256,10, 10);rt_thread_init(&thread_handle2,"thread2",thread_test2,NULL,thread_stack2,256,10, 10);rt_thread_startup(&thread_handle1);rt_thread_startup(&thread_handle2);rt_thread_delay(1000);rt_thread_detach(&thread_handle2);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */rt_thread_delay(100);/* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}实验现象:
1.在串口终端观察打印现象

