目录
概述
1 线程的概念
1.1 线程定义
1.2 线程的本质定义
1.3 线程的核心组成要素
1.4 线程与进程的对比
1.5 线程在RTOS中的关键特性
1.6 线程的同步与通信
1.7 线程在嵌入式系统的特殊考量
1.8 多线程编程模型
2 Zephyr RTOS 中线程
2.1 创建线程的步骤
2.2 Zephyr RTOS 中线程定义
2.3 关键API函数
2.4 线程中的睡眠函数
3 线程应用实践
3.1 完整线程定义模板
3.1.1 源代码
3.1.2 关键细节
3.2 两个线程交替输出信息
本文主要介绍zephyr OS 线程的使用,在嵌入式RTOS中,合理使用线程是构建高效可靠系统的关键。Zephyr提供了丰富的线程管理API(k_thread_create()
, k_thread_suspend()
等),开发者需根据具体需求平衡线程数量、优先级和资源消耗。
线程基础概念
线程状态:就绪(Ready)、挂起(Pending)、运行(Running)、终止(Terminated)
优先级:数值越小优先级越高(0为最高,负数为协程)
调度方式:
协作式(Cooperative):线程主动让出CPU(
k_yield()
)抢占式(Preemptive):高优先级线程抢占低优先级线程
时间片轮转(Round Robin):同优先级线程轮流执行
线程是:
轻量级进程:比传统进程更小的执行单元
独立执行流:拥有自己的程序计数器、栈和寄存器状态
调度基本单位:操作系统调度的最小单元
资源共享实体:同一进程中的线程共享内存空间和资源
组件 | 作用 | 特性 |
---|---|---|
程序计数器(PC) | 记录下一条指令地址 | 线程私有 |
寄存器集合 | 存储当前计算状态 | 线程私有 |
栈空间 | 存储局部变量/函数调用链 | 线程私有 |
线程控制块(TCB) | 存储管理信息(状态、优先级等) | 内核管理 |
特性 | 进程 | 线程 |
---|---|---|
资源分配 | 独立内存空间 | 共享进程资源 |
创建开销 | 大(MB级) | 小(KB级) |
切换开销 | 高(需MMU切换) | 低(仅寄存器) |
通信方式 | IPC(管道、套接字等) | 共享内存 |
容错性 | 一个崩溃不影响其他 | 一个崩溃可能影响同进程所有线程 |
1) 执行状态
就绪(Ready):等待CPU分配
运行(Running):正在CPU执行
阻塞(Blocked):等待事件(I/O、信号量等)
终止(Terminated):执行完成或被终止
2) 优先级机制
固定优先级调度(Zephyr默认)
优先级继承(解决优先级反转)
优先级天花板协议
3)调度策略
类型 | 特点 | 适用场景 |
---|---|---|
抢占式 | 高优先级立即抢占 | 实时性要求高 |
协作式 | 线程主动让出CPU | 低功耗系统 |
时间片轮转 | 同优先级公平分配 | 计算密集型 |
1)关键机制:
-1)互斥锁(Mutex):保护临界区
K_MUTEX_DEFINE(my_mutex);
k_mutex_lock(&my_mutex, K_FOREVER);
// 临界区操作
k_mutex_unlock(&my_mutex);
- 2)信号量(Semaphore):资源计数/同步
-3)消息队列(Message Queue):线程间数据传输
-4) 事件标志(Event Flags):多事件通知
2)典型问题:
竞态条件:未保护的共享数据访问
死锁:多个线程相互等待资源
优先级反转:低优先级线程阻塞高优先级线程
栈空间优化
精确计算最大栈深度
使用栈分析工具(如Zephyr的
CONFIG_THREAD_ANALYZER
)典型大小:512B-4KB(无OS) vs 1-8KB(RTOS)
实时性保证
最坏执行时间(WCET)分析
中断延迟控制
优先级驱动设计
资源约束
有限的内存和CPU资源
无MMU情况下的内存保护缺失
低功耗要求(休眠态线程管理)
模型 | 特点 | 示例场景 |
---|---|---|
主从模型 | 主线程分配任务,工作线程执行 | 传感器数据采集 |
流水线模型 | 数据流经多个处理线程 | 图像处理链路 |
客户端-服务器 | 客户端请求,服务器处理 | 网络通信协议栈 |
对等模型 | 线程平等协作 | 分布式计算 |
step-1: 定义线程栈
#define THREAD_STACK_SIZE 1024
K_THREAD_STACK_DEFINE(my_thread_stack, THREAD_STACK_SIZE);
step-2: 定义线程结构体
struct k_thread my_thread_data;
step-3 : 编写线程函数
void my_thread_entry(void *p1, void *p2, void *p3)
{
while (1) {
printk("Thread running!\n");
k_msleep(1000); // 睡眠1秒
}
}
step-4: 创建并启动线程
k_tid_t thread_id = k_thread_create(
&my_thread_data, // 线程结构体指针
my_thread_stack, // 栈空间
K_THREAD_STACK_SIZEOF(my_thread_stack), // 栈大小
my_thread_entry, // 线程入口函数
NULL, NULL, NULL, // 入口函数参数(最多3个)
K_PRIO_COOP(5), // 优先级(5,协作式)
0, // 线程选项(通常为0)
K_NO_WAIT // 启动延迟(立即启动)
);
1) 线程定义的核心组件
组件 | 说明 | 示例 |
---|---|---|
线程控制块 (TCB) | 存储线程状态信息 | struct k_thread my_thread; |
线程栈 | 分配执行空间 | K_THREAD_STACK_DEFINE(my_stack, 1024); |
线程函数 | 线程入口点 | void thread_fn(void *a, void *b, void *c) {...} |
线程属性 | 优先级、选项等 | K_PRIO_PREEMPT(5), K_FP_REGS |
函数 | 作用 |
---|---|
k_thread_create() |
创建并启动线程 |
k_thread_suspend() |
挂起线程 |
k_thread_resume() |
恢复挂起的线程 |
k_sleep() / k_msleep() |
线程睡眠(毫秒/秒) |
k_yield() |
主动让出CPU |
k_thread_join() |
等待线程结束 |
k_thread_abort() |
终止线程 |
函数 | 线程状态 | 恢复条件 | 适用场景 |
---|---|---|---|
k_yield() |
保持就绪(Ready) | 随时可被调度 | 主动让出 CPU |
k_sleep() |
进入阻塞(Pending) | 超时后恢复 | 需要延时等待 |
k_msleep() |
进入阻塞(Pending) | 超时后恢复 | 毫秒级延时 |
#include
/* 1. 定义线程栈 */
#define MY_STACK_SIZE 1024
K_THREAD_STACK_DEFINE(my_thread_stack, MY_STACK_SIZE);
/* 2. 定义线程控制块 */
static struct k_thread my_thread;
/* 3. 线程函数实现 */
void my_thread_entry(void *arg1, void *arg2, void *arg3)
{
int *param = (int *)arg1; // 参数转换
while (1) {
printk("Thread running: %d\n", *param);
k_msleep(500);
// 协作式线程需要主动让出
k_yield();
}
}
/* 4. 创建并启动线程 */
int init_my_thread(void)
{
int thread_param = 42; // 传递给线程的参数
k_tid_t tid = k_thread_create(
&my_thread, // 线程控制块
my_thread_stack, // 栈空间
K_THREAD_STACK_SIZEOF(my_thread_stack), // 栈大小
my_thread_entry, // 入口函数
&thread_param, NULL, NULL, // 参数 (最多3个)
K_PRIO_PREEMPT(5), // 优先级 (抢占式)
0, // 线程选项
K_NO_WAIT // 启动延迟
);
return (tid != NULL) ? 0 : -1; // 检查创建是否成功
}
1)线程栈定义
// 静态定义(推荐)
K_THREAD_STACK_DEFINE(stack_name, size_in_bytes);
// 动态分配(需启用CONFIG_HEAP_MEM_POOL_SIZE)
k_thread_stack_t *dyn_stack = k_thread_stack_alloc(size, align);
2)线程参数传递
线程入口函数支持最多3个参数:
// 创建时传递参数
k_thread_create(...,
(void *)&device, // arg1
(void *)&config, // arg2
(void *)&status // arg3
);
// 在线程中访问
void thread_fn(void *arg1, void *arg2, void *arg3)
{
struct device *dev = (struct device *)arg1;
struct config *cfg = (struct config *)arg2;
int *status_flag = (int *)arg3;
}
#include
K_THREAD_STACK_DEFINE(threadA_stack, 512);
K_THREAD_STACK_DEFINE(threadB_stack, 512);
struct k_thread threadA_data, threadB_data;
void threadA(void *, void *, void *) {
while (1) {
printk("A");
k_msleep(100);
}
}
void threadB(void *, void *, void *) {
while (1) {
printk("B");
k_msleep(100);
}
}
int main(void) {
k_thread_create(&threadA_data, threadA_stack,
K_THREAD_STACK_SIZEOF(threadA_stack),
threadA, NULL, NULL, NULL,
5, 0, K_NO_WAIT);
k_thread_create(&threadB_data, threadB_stack,
K_THREAD_STACK_SIZEOF(threadB_stack),
threadB, NULL, NULL, NULL,
5, 0, K_NO_WAIT);
return 0;
}