问题描述:

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);
    }

kthread_create wake_up_process kthread_run_linux内核开发头文件

// 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;
}

kthread_create wake_up_process kthread_run_linux内核开发头文件

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)

kthread_create wake_up_process kthread_run_linux内核开发头文件

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;
    }

kthread_create wake_up_process kthread_run_linux内核开发头文件

// 打印线程启动信息(包含 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");

kthread_create wake_up_process kthread_run_linux内核开发头文件

kthread_create wake_up_process kthread_run_linux内核开发头文件

图片

linux内核开发头文件_kthread_create wake_up_process kthread_run

/*
 * 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

推论

linux内核开发头文件_kthread_create wake_up_process kthread_run

输出结论

待查资料问题参考链接

Tagged:
Author

这篇优质的内容由TA贡献而来

刘遄

《Linux就该这么学》书籍作者,RHCA认证架构师,教育学(计算机专业硕士)。

发表回复