【Linux API】kthread的使用

本文详细分析了Linux内核中的kthread使用,包括如何创建和启动内核线程,以及线程管理的相关API。通过实例展示了kthread_create和kthread_run的区别,并提到了kthread_stop和kthread_should_stop函数在管理线程过程中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一,内核实例分析

先来分析一下一个实例,这个例子主要是创建一个内核线程,用来打印GPIO信息,当线程没有收到停止的指令时,一直打印。

int config_gpio_thread(void *tmp_gpio_num) //回调函数,返回值必须是int ,且参数必须是void *
{
         int gpio_num = *((int *)tmp_gpio_num);//类型强转,由void*转成int*,取值
         while(!kthread_should_stop()) //当kthread_should_stop()函数没有被调用的时候,就一直打印。
                {
                 gpio_direction_output(gpio_num, 0);
                 printk("the gpio get  a value of :%d:=========buqing.wang test \n",__gpio_get_value(gpio_num));
                 msleep(500);
                 gpio_direction_output(gpio_num, 2);     
                 printk("the gpio get  a value of :%d:=============buqing.wang test \n",__gpio_get_value(gpio_num));
                 msleep(500);
                }           
    return 0;
} 

//具体的操作部分
int handle_gpio_thead(int num)  
{
struct task_struct * gpio_thread;  //任务结构体
void* gpio_num;
gpio_num=#
gpio_thread=kthread_create(config_gpio_thread,&gpio_num,"gpio_thread");//第二个参数是回调函数的参数,必须是void*
wake_up_process(gpio_thread); //唤醒线程开始工作
msleep(5000);  //5s后,叫停线程
kthread_stop(gpio_thread);//这个函数调用后,kthread_should_stop()返回值由false变成true
    return 0;
} 

二,关于线程创建相关的API

创建Kthread主要有两种方法
第一种就是如上所述:
kthread_create(threadfn, data, namefmt, arg…),宏,返回一个task_struct *类型的数据址。创建线程任务,threadfn 线程的回调函数,data是参数,那么format是线程名字。
回调函数返回值必须是int,参数必须是void*
wake_up_process(gpio_thread),启动线程

第二种方法:

kthread_run(threadfn, data, namefmt, …) 直接创建线程并且启动

其他线程相关的API:
int kthread_stop(struct task_struct *k); //让线程结束
bool kthread_should_stop(void); //判断线程状态

参考文件:

kernel/include/linux/kthread.h

#ifndef _LINUX_KTHREAD_H
#define _LINUX_KTHREAD_H
/* Simple interface for creating and stopping kernel threads without mess. */
#include <linux/err.h>
#include <linux/sched.h>

__printf(4, 5)
struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
                       void *data,
                       int node,
                       const char namefmt[], ...);

#define kthread_create(threadfn, data, namefmt, arg...) \
    kthread_create_on_node(threadfn, data, -1, namefmt, ##arg)


struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
                      void *data,
                      unsigned int cpu,
                      const char *namefmt);

/**
 * kthread_run - create and wake a thread.
 * @threadfn: the function to run until signal_pending(current).
 * @data: data ptr for @threadfn.
 * @namefmt: printf-style name for the thread.
 *
 * Description: Convenient wrapper for kthread_create() followed by
 * wake_up_process().  Returns the kthread or ERR_PTR(-ENOMEM).
 */
#define kthread_run(threadfn, data, namefmt, ...)              \
({                                     \
    struct task_struct *__k                        \
        = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
    if (!IS_ERR(__k))                          \
        wake_up_process(__k);                      \
    __k;                                   \
})

void kthread_bind(struct task_struct *k, unsigned int cpu);
int kthread_stop(struct task_struct *k);
bool kthread_should_stop(void);
bool kthread_should_park(void);
bool kthread_freezable_should_stop(bool *was_frozen);
void *kthread_data(struct task_struct *k);
void *probe_kthread_data(struct task_struct *k);
int kthread_park(struct task_struct *k);
void kthread_unpark(struct task_struct *k);
void kthread_parkme(void);

int kthreadd(void *unused);
extern struct task_struct *kthreadd_task;
extern int tsk_fork_get_node(struct task_struct *tsk);

/*
 * Simple work processor based on kthread.
 *
 * This provides easier way to make use of kthreads.  A kthread_work
 * can be queued and flushed using queue/flush_kthread_work()
 * respectively.  Queued kthread_works are processed by a kthread
 * running kthread_worker_fn().
 */
st
<think>好的,用户想了解kthread_run的代码示例。首先,我需要回忆一下kthread_run在内核中的用途。它用于创建并启动一个内核线程,对吧?记得它其实是kthread_create_on_node和wake_up_process的宏组合。所以,用户可能需要一个示例来展示如何正确使用这个函数。 接下来,我应该考虑用户可能的背景。可能是一个刚开始学习内核编程的开发者,或者是在调试驱动程序时遇到问题的人。他们需要知道如何正确编写线程函数,处理模块的初始化和退出,以及如何传递参数。此外,用户可能关心错误处理和资源清理,比如在模块卸载时停止线程。 然后,我需要确保代码示例符合内核编程的标准,比如使用正确的头文件,比如linux/kthread.h、linux/module.h等。线程函数应该遵循特定的签名,返回int,并接受void*参数。还要注意线程的终止条件,比如使用kthread_should_stop()来检查是否需要退出循环。 另外,要注意模块的初始化(module_init)和退出(module_exit),在退出时使用kthread_stop来终止线程,并等待其完成。参数传递的例子可能会用指针传递一个结构体或整数,这里可能需要用int作为例子比较简单。 可能用户在使用时容易出错的地方,比如忘记检查kthread_run的返回值,导致空指针解引用。所以在示例中必须包含错误检查,用IS_ERR判断,并处理错误情况。 还要注意代码的可读性,添加必要的注释,解释每个步骤的作用,比如线程函数的循环,模块的加载和卸载过程。这样用户能更清晰地理解示例的结构。 最后,确保示例代码的语法正确,比如使用正确的宏和函数调用方式,以及模块的许可证声明(MODULE_LICENSE)。可能还需要提醒用户在内核编程中的一些注意事项,比如不能直接访问用户空间,避免长时间占用CPU等。</think>以下是一个使用 `kthread_run` 的 Linux 内核模块代码示例及分步说明: --- ### 1. 头文件引入 ```c #include <linux/kthread.h> // 内核线程相关 #include <linux/module.h> // 模块必备头文件 #include <linux/delay.h> // 延时函数 ``` --- ### 2. 定义线程参数和状态 ```c static struct task_struct *my_kthread; // 内核线程指针 static int thread_data = 2023; // 传递给线程的参数 ``` --- ### 3. 线程函数实现 ```c static int my_thread_func(void *data) { int *value = (int *)data; while (!kthread_should_stop()) { // 检查停止信号 printk(KERN_INFO "Thread running, data: %d\n", *value); msleep(2000); // 睡眠2秒(不可用用户空间的sleep) } printk(KERN_INFO "Thread exiting\n"); return 0; } ``` --- ### 4. 模块初始化(创建线程) ```c static int __init my_module_init(void) { // 创建并启动线程 my_kthread = kthread_run(my_thread_func, &thread_data, "my_kthread"); if (IS_ERR(my_kthread)) { // 必须检查错误 printk(KERN_ERR "Failed to create thread\n"); return PTR_ERR(my_kthread); } printk(KERN_INFO "Module loaded\n"); return 0; } ``` --- ### 5. 模块退出(清理线程) ```c static void __exit my_module_exit(void) { if (my_kthread) { kthread_stop(my_kthread); // 发送停止信号 printk(KERN_INFO "Thread stopped\n"); } printk(KERN_INFO "Module unloaded\n"); } ``` --- ### 6. 声明模块入口/出口 ```c module_init(my_module_init); module_exit(my_module_exit); MODULE_LICENSE("GPL"); // 必须声明许可证 ``` --- ### 关键点解析: 1. **线程创建流程**: - `kthread_run` 是宏定义: ```c #define kthread_run(threadfn, data, namefmt, ...) ``` - 实际展开为 `kthread_create_on_node` + `wake_up_process` 2. **停止机制**: - 使用 `kthread_should_stop()` 作为循环条件 - 模块退出时必须调用 `kthread_stop` 3. **注意事项**: - 线程函数不能直接访问用户空间 - 睡眠必须使用内核API(如 `msleep`) - 打印信息使用 `printk` 而非 `printf` - 必须实现完整的错误检查 --- ### 验证方式: 1. 编译模块后插入: ```bash sudo insmod example.ko ``` 2. 查看内核日志: ```bash dmesg | tail -n 20 ``` 3. 预期输出: ``` Module loaded Thread running, data: 2023 ``` 4. 卸载模块: ```bash sudo rmmod example ``` 5. 日志更新: ``` Thread exiting Thread stopped Module unloaded ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值