一、线程
1.1 线程的概念
RT-Thread 的线程调度器是抢占式的,保证最高优先级的线程执行。有一下几种抢占的情形:
当一个线程使比它优先级高的线程满足条件,高优先级线程会立刻执行。
如果这个过程发生在中断中,中断结束后高优先级线程立刻执行。
1.2 关于线程的知识点
1.2.1 线程栈
当切换线程时,当前线程上下文会被保存在线程栈中,恢复运行时从线程栈恢复上下文。
线程栈大小确定方法:先分配1k,运行起来后通过finsh输入list_thread查看线程栈的深度,在此基础上加上余量确定线程栈的大小。
线程栈的增长方向:与芯片有关,在3.1.0之前的版本,只支持高地质向低地址增长。
1.2.2 线程状态
RT_THREAD_INIT:初始状态,线程刚创建时的状态。
RT_THREAD_READY:就绪态,当前线程运行完让出cpu时下一个就绪态的线程开始运行。
RT_THREAD_RUNNING:运行态,在单核系统中,rt_thread_self()函数查看当前运行的线程。
RT_THREAD_SUSPEND:挂起态,因为得不到资源或主动延时产生挂起(也称阻塞)。
RT_THREAD_CLOSE:结束态,线程结束。
1.2.3 线程优先级
rtthread最大支持256个线程(一般选择32个),数值越小,优先级越高,0为最高优先级,最低优先级分配给空闲线程。
1.2.4 时间片
仅对优先级相同的线程有用,用于限制线程的运行时长,单位是相同节拍。
1.2.5 入口函数
entry是线程的入口函数,是线程实现预期功能的函数,注意在无限循环线程中要有延时或挂起等操作来让出cpu使用权,否则低优先级的线程无法得到执行。
1.2.6 线程的错误码说明
#define RT_EOK 0 /* 无 错 误 */
#define RT_ERROR 1 /* 普 通 错 误 */
#define RT_E
tiMEOUT 2 /* 超 时 错 误 */
#define RT_EFULL 3 /* 资 源 已 满 */
#define RT_EEMPTY 4 /* 无 资 源 */
#define RT_ENOMEM 5 /* 无 内 存 */
#define RT_ENOSYS 6 /* 系 统 不 支 持 */
#define RT_EBUSY 7 /* 系 统 忙 */
#define RT_EIO 8 /* IO 错 误 */
#define RT_EINTR 9 /* 中 断 系 统 调 用 */
#define RT_EINVAL 10 /* 非 法 参 数 */
二、线程api
//动态创建线程
/*
name:线程名称
entry:入口函数
parameter:入口函数参数
stack_size:栈大小,单位:字节
priority:优先级
tick:时间片,单位:系统节拍
*/
rt_thread_t rt_thread_create(const char* name,
void (*entry)(void* parameter),
void* parameter,
rt_uint32_t stack_size,
rt_uint8_t priority,
rt_uint32_t tick);
//删除动态创建的线程
/*
thread:线程句柄
*/
rt_err_t rt_thread_delete(rt_thread_t thread);
//初始化线程
/*
thread:线程结构体指针
name:线程名称
entry:入口函数
parameter:入口函数参数
stack_start:栈起始地址
stack_size:栈大小
priority:优先级
tick:时间片
*/
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);
//初始化出来的线程的脱离
/*
thread:线程句柄
*/
rt_err_t rt_thread_detach (rt_thread_t thread);
//启动线程
/*
thread:线程句柄
*/
rt_err_t rt_thread_startup(rt_thread_t thread)
//获取当前线程
/*
返回当前线程的句柄
*/
rt_thread_t rt_thread_self(void);
//让出资源
rt_err_t rt_thread_yield(void);
//睡眠,可以让线程挂起指定的时间
/*
tick:睡眠的时间
*/
rt_err_t rt_thread_sleep(rt_tick_t tick);
rt_err_t rt_thread_delay(rt_tick_t tick);
rt_err_t rt_thread_mdelay(rt_int32_t ms);
`
//线程挂起,不推荐使用
/*
thread:线程句柄
*/
rt_err_t rt_thread_suspend (rt_thread_t thread);
//恢复线程
/*
thread:线程句柄
*/
rt_err_t rt_thread_resume (rt_thread_t thread);
//控制线程
/*
thread:线程句柄
cmd:控制命令
cmd支持的命令:
RT_THREAD_CTRL_CHANGE_PRIORITY:更改线程优先级
RT_THREAD_CTRL_STARTUP:运行线程
RT_THREAD_CTRL_CLOSE:关闭线程
arg:控制参数
*/
rt_err_t rt_thread_control(rt_thread_t thread, rt_uint8_t cmd, void* arg);
三、示例
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-08-24 yangjie the first version
*/
/*
* 程序清单:创建、初始化/脱离线程
*
* 这个例子会创建两个线程,一个动态线程,一个静态线程。
* 静态线程在运行完毕后自动被系统脱离,动态线程一直打印计数。
*/
#include
#define THREAD_PRIORITY 25
#define THREAD_STACK_SIZE 512
#define THREAD_TIMESLICE 5
static rt_thread_t tid1 = RT_NULL;
/* 线程1的入口函数 */
static void thread1_entry(void *parameter)
{
rt_uint32_t count = 0;
while (1)
{
/* 线程1采用低优先级运行,一直打印计数值 */
rt_kprintf("thread1 count: %dn", count ++);
rt_thread_mdelay(500);
}
}
ALIGN(RT_ALIGN_SIZE)
static char thread2_stack[1024];
static struct rt_thread thread2;
/* 线程2入口 */
static void thread2_entry(void *param)
{
rt_uint32_t count = 0;
/* 线程2拥有较高的优先级,以抢占线程1而获得执行 */
for (count = 0; count < 10 ; count++)
{
/* 线程2打印计数值 */
rt_kprintf("thread2 count: %dn", count);
}
rt_kprintf("thread2 exitn");
/* 线程2运行结束后也将自动被系统脱离 */
}
/* 线程示例 */
int thread_sample(void)
{
/* 创建线程1,名称是thread1,入口是thread1_entry*/
tid1 = rt_thread_create("thread1",
thread1_entry, RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY, THREAD_TIMESLICE);
/* 如果获得线程控制块,启动这个线程 */
if (tid1 != RT_NULL)
rt_thread_startup(tid1);
/* 初始化线程2,名称是thread2,入口是thread2_entry */
rt_thread_init(&thread2,
"thread2",
thread2_entry,
RT_NULL,
&thread2_stack[0],
sizeof(thread2_stack),
THREAD_PRIORITY - 1, THREAD_TIMESLICE);
rt_thread_startup(&thread2);
return 0;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(thread_sample, thread sample);