问题描述:
在 Linux 内核中,创建内核线程的常见方式有 2 种:kthread_create() + wake_up_process()、kthread_run()(简化版)
日志
添加打印日志信息
剖析步骤
第1步:
第2步:
...
代码片断
一、kthread_create()+wake_up_process()这是最基础的方法:先创建线程(初始为睡眠状态)linux内核开发头文件android linuxlinux培训机构,再自动唤起。适宜须要先初始化资源再启动线程的场景。
/*
* @Author: your name
* @Date: 2025-09-02 14:17:29
* @LastEditTime: 2025-09-02 14:22:51
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: linux-4.14.143driversgpudrmtestkthread.c
*/
#include
#include
#include
#include
/*
创建内核线程的步骤如下:
1. 使用kthread_create()创建线程,返回线程结构体指针。
2. 初始化线程退出标志,如kthread1_should_stop = 0;。
3. 使用wake_up_process()唤醒线程,启动线程。
4. 线程处理函数中,使用kthread_should_stop()检查退出标志,循环执行任务。
5. 线程退出时,设置退出标志,使用kthread_stop()等待线程退出。
*/
// 线程指针
static struct task_struct *kthread1;
// 线程退出标志
static int kthread1_should_stop;
// 线程处理函数
static int kthread1_func(void *data)
{
printk(KERN_INFO "[kthread1] 线程启动(CPU:%d)n", smp_processor_id());
// 循环执行,直到退出标志被设置
while (!kthread1_should_stop) {
printk(KERN_INFO "[kthread1] 运行中...n");
msleep(2000); // 睡眠2秒(进程上下文可睡眠)
// 检查是否被要求退出
if (kthread_should_stop())
break;
}
printk(KERN_INFO "[kthread1] 线程退出n");
return 0;
}
static int __init kthread_demo_init(void)
{
printk(KERN_INFO "内核线程示例初始化...n");
// 1. 创建线程(初始为睡眠状态)
/*
可以看到创建线程的名称
836 root [kthread1]
*/
kthread1 = kthread_create(kthread1_func, NULL, "kthread1");
if (IS_ERR(kthread1)) {
printk(KERN_ERR "创建kthread1失败!n");
return PTR_ERR(kthread1);
}

// 2. 唤醒线程(开始执行),启动线程
wake_up_process(kthread1);
kthread1_should_stop = 0; // 初始化退出标志
printk(KERN_INFO "kthread1创建并启动成功n");
return 0;
}
static void __exit kthread_demo_exit(void)
{
// 停止线程
kthread1_should_stop = 1;
kthread_stop(kthread1); // 等待线程退出
printk(KERN_INFO "kthread1已停止n");
}
module_init(kthread_demo_init);
module_exit(kthread_demo_exit);
MODULE_LICENSE("GPL");
二、kthread_run()(推荐)kthread_run()是内核提供的宏,封装了kthread_create()和wake_up_process(),一步完成线程创建并启动linux内核开发头文件,用法更简练,适宜大多数场景。
/*
* @Author: your name
* @Date: 2025-09-02 14:26:03
* @LastEditTime: 2025-09-02 14:29:37
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: linux-4.14.143driversgpudrmtestkthread2.c
*/
#include
#include
#include
#include
/*
使用kthread_run创建线程步骤如下:
1. 使用kthread_run()创建线程,返回线程结构体指针。
2. 线程处理函数中,使用kthread_should_stop()检查退出信号,循环执行任务。
3. 线程退出时,设置退出信号,使用kthread_stop()等待线程退出。
*/
// 线程指针
static struct task_struct *kthread2;
// 线程处理函数
static int kthread2_func(void *data)
{
printk(KERN_INFO "[kthread2] 线程启动(CPU:%d)n", smp_processor_id());
// 循环执行,通过kthread_should_stop()检查退出信号
while (!kthread_should_stop()) {
printk(KERN_INFO "[kthread2] 运行中...n");
msleep(3000); // 睡眠3秒
}
printk(KERN_INFO "[kthread2] 线程退出n");
return 0;
}
static int __init kthread_demo_init(void)
{
printk(KERN_INFO "内核线程示例初始化...n");
// 创建并启动线程(一步完成)
kthread2 = kthread_run(kthread2_func, NULL, "kthread2");
if (IS_ERR(kthread2)) {
printk(KERN_ERR "创建kthread2失败!n");
return PTR_ERR(kthread2);
}
printk(KERN_INFO "kthread2创建并启动成功n");
return 0;
}

static void __exit kthread_demo_exit(void)
{
// 停止线程(kthread_stop会发送退出信号并等待)
if (!IS_ERR(kthread2)) {
kthread_stop(kthread2);
printk(KERN_INFO "kthread2已停止n");
}
}
module_init(kthread_demo_init);
module_exit(kthread_demo_exit);
MODULE_LICENSE("GPL");
设置内核线程优先级
/*
* @Author: your name
* @Date: 2025-09-02 15:18:52
* @LastEditTime: 2025-09-02 15:39:05
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: linux-4.14.143driversgpudrmtestkthead3.c
*/
#include
#include
#include
#include // 必须包含此头文件,定义了struct sched_param
#include // 实时调度相关辅助定义
#include
#include
// 实时线程指针
static struct task_struct *rt_thread = NULL;
// 线程退出标志
static bool rt_thread_exit = false;
// 实时线程处理函数
static int rt_thread_func(void *data)
{
pr_info("[RT线程] 启动成功,PID:%d,实时优先级:%dn",
current->pid, current->rt_priority);
// 线程主循环
while (!rt_thread_exit && !kthread_should_stop()) {
pr_info("[RT线程] 运行中CPU:%dn", smp_processor_id());
msleep(1000); // 模拟业务逻辑
}
pr_info("[RT线程] 退出n");
return 0;
}
static int __init rt_kthread_init(void)
{
struct sched_param param;
int ret;
pr_info("=== 实时线程创建示例(创建时设置优先级) ===n");
// 1. 创建线程(初始为睡眠状态,未被调度)
rt_thread = kthread_create(rt_thread_func, NULL, "init_rt_kthread");
if (IS_ERR(rt_thread)) {
ret = PTR_ERR(rt_thread);
pr_err("创建线程失败,ret=%dn", ret);
return ret;
}
// 2. 创建后、唤醒前,直接设置实时优先级(关键步骤), 这个值越大优先级越高
param.sched_priority = 60; // 实时优先级 60(1~99)

ret = sched_setscheduler(rt_thread, SCHED_FIFO, ¶m);
if (ret != 0) {
pr_err("设置实时优先级失败,ret=%dn", ret);
kthread_stop(rt_thread); // 清理失败的线程
rt_thread = NULL;
return ret;
}
// 3. 唤醒线程(此时线程以设置好的优先级开始运行)
wake_up_process(rt_thread);
pr_info("实时线程已创建并唤醒PID=%dn", rt_thread->pid);
return 0;
}
static void __exit rt_kthread_exit(void)
{
if (!IS_ERR(rt_thread)) {
rt_thread_exit = true;
kthread_stop(rt_thread); // 等待线程退出
rt_thread = NULL;
}
pr_info("驱动卸载完成n");
}
module_init(rt_kthread_init);
module_exit(rt_kthread_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("RT Kernel Thread (Set Priority on Create)");
设置实时和普通内核线程优先级
#include
#include
#include
#include // 调度策略、优先级相关定义
#include // 实时调度相关接口
#include // msleep 函数
#include // 内核打印
#include
/*
设置内核线程优先级步骤如下:
1. 创建线程
2. 设置线程优先级
3. 唤醒线程
*/
// 内核线程指针(分别对应实时优先级线程和普通优先级线程)
static struct task_struct *rt_thread = NULL; // 实时优先级线程
static struct task_struct *nice_thread = NULL;// 普通优先级线程
// 线程退出标志(避免线程在卸载时残留)
static bool rt_thread_exit = false;
static bool nice_thread_exit = false;
/*********************************************************************
* 实时优先级线程处理函数(SCHED_FIFO 策略,优先级 50)
********************************************************************/
static int rt_thread_func(void *data)
{
struct sched_param param;
int ret;
// 1. 设置实时调度策略和优先级
param.sched_priority = 50; // 实时优先级范围:1~99(值越大优先级越高)
ret = sched_setscheduler(current, SCHED_FIFO, ¶m);
if (ret != 0) {
pr_err("[RT线程] 设置实时优先级失败,ret=%dn", ret);
return ret;
}

// 打印线程启动信息(包含 PID、优先级、调度策略)
pr_info("[RT线程] 启动成功,PID=%d,调度策略=SCHED_FIFO,实时优先级=%dn",
current->pid, param.sched_priority);
// 2. 线程主循环(处理业务逻辑,直到退出标志置位)
while (!rt_thread_exit && !kthread_should_stop()) {
// 模拟业务逻辑(如实时数据处理)
pr_info("[RT线程] 运行中...(当前CPU:%d)n", smp_processor_id());
// 睡眠 1 秒(实时线程也可睡眠,但需确保唤醒后能抢占CPU)
msleep(1000);
}
// 3. 线程退出清理
pr_info("[RT线程] 退出!n");
return 0;
}
/*********************************************************************
* 普通优先级线程处理函数(SCHED_NORMAL 策略,通过 nice 值调整优先级)
********************************************************************/
static int nice_thread_func(void *data)
{
int ret;
int target_nice = -10; // nice 值范围:-20(最高)~19(最低)
// 1. 设置普通优先级(通过 nice 值调整)
set_user_nice(current, target_nice);
// 打印线程启动信息(包含 PID、nice 值)
pr_info("[普通线程] 启动成功,PID=%d,调度策略=SCHED_NORMAL,nice值=%dn",
current->pid, task_nice(current));
// 2. 线程主循环(处理非实时业务逻辑)
while (!nice_thread_exit && !kthread_should_stop()) {
// 模拟业务逻辑(如非实时数据统计)
pr_info("[普通线程] 运行中...(当前CPU:%d)n", smp_processor_id());
// 睡眠 2 秒(普通线程睡眠不影响实时任务)
msleep(2000);
}
// 3. 线程退出清理
pr_info("[普通线程] 退出!n");
return 0;
}
/*********************************************************************
* 驱动初始化函数(模块加载时执行)
********************************************************************/
static int __init kthread_priority_init(void)
{
pr_info("=== 内核线程优先级示例驱动初始化 ===n");
// 1. 创建实时优先级线程(线程名:rt_kthread)
rt_thread = kthread_run(rt_thread_func, // 线程处理函数
NULL, // 传递给线程的参数
"rt_kthread"); // 线程名(ps 命令可查看)
if (IS_ERR(rt_thread)) {
goto err_rt_thread;
}
// 2. 创建普通优先级线程(线程名:nice_kthread)
nice_thread = kthread_run(nice_thread_func,
NULL,
"nice_kthread");
if (IS_ERR(nice_thread)) {
goto err_nice_thread;
}
pr_info("驱动初始化完成!可通过 'ps -ef | grep kthread' 查看线程n");
return 0;
// 错误处理(创建失败时清理资源)
err_nice_thread:
rt_thread_exit = true;
kthread_stop(rt_thread); // 停止已创建的实时线程
err_rt_thread:
return 0;
}
/*********************************************************************
* 驱动卸载函数(模块卸载时执行)
********************************************************************/
static void __exit kthread_priority_exit(void)
{
pr_info("n=== 内核线程优先级示例驱动卸载 ===n");
// 1. 停止实时线程
if (!IS_ERR(rt_thread)) {
rt_thread_exit = true;
kthread_stop(rt_thread); // 等待线程退出
rt_thread = NULL;
}
// 2. 停止普通线程
if (!IS_ERR(nice_thread)) {
nice_thread_exit = true;
kthread_stop(nice_thread);
nice_thread = NULL;
}
pr_info("驱动卸载完成!n");
}
// 注册驱动入口和出口函数
module_init(kthread_priority_init);
module_exit(kthread_priority_exit);
// 模块许可证(GPL 许可证,确保内核兼容性)
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Linux Kernel Thread Priority Demo");
MODULE_AUTHOR("Your Name");
MODULE_VERSION("1.0");


图片

/*
* Scheduling policies
*/
#define SCHED_NORMAL 0
#define SCHED_FIFO 1
#define SCHED_RR 2
#define SCHED_BATCH 3
/* SCHED_ISO: reserved but not implemented yet */
#define SCHED_IDLE 5
#define SCHED_DEADLINE 6
推论

输出结论
待查资料问题参考链接
