问题描述:
在 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
推论

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