内核线程是工作在内核空间的,不属于任何一个进程,可以发生睡眠。可以用内核线程来进行一些循环的动作,比如通过循环拉高拉低gpio设置成方波输出的信号来模拟pwm信号,比如循环控制led的闪灯效果等等都可以使用到内核线程kthread_create接口函数。

内核线程的相关代码目录:

include/linux/kthread.h 
kernel/kthread.c

1、创建并启动一个内核线程

struct task_struct *kthread_create(int (*threadfn)(void *data),
                               void *data,
                               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;                                                     \
})

其中kthread_create()只是创建一个内核线程,但并没有启动,需要调用wake_up_process()来启动线程,所以内核又帮我们定义了一个宏kthread_run来帮我们搞定。内核线程创建成功后,会返回一个struct task_struct对象指针,方便我们的后续操作。

2、关闭一个内核线程

int kthread_stop(struct task_struct *k);

这个调用是会阻塞等待,直到内核线程k退出为止。原因为此函数内部会调用wait_for_completion()的方法(通过等待队列来实现),阻塞等待内核线程自身的退出。

3.内核线程函数,如何判断自身需要退出:

 int kthread_should_stop(void);

如果该内核线程已经被设置stop标志了,则会返回1,否则返回0。

这里列举一个使用内核线程的简单的demo代码,可作为参考:

demo代码实现的是在模块初始化的时候创建一个内核线程,此内核线程的功能是每隔5秒中打印一条log信息。当我们卸载模块的时候,会关闭该内核线程。

#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/delay.h>
 
 
#define ENTER() printk(KERN_DEBUG "%s() Enter", __func__)
#define EXIT() printk(KERN_DEBUG "%s() Exit", __func__)
#define ERR(fmt, args...) printk(KERN_ERR "%s()-%d: " fmt "\n", __func__, __LINE__, ##args)
#define DBG(fmt, args...) printk(KERN_DEBUG "%s()-%d: " fmt "\n", __func__, __LINE__, ##args)
 
static struct task_struct *test_kthread = NULL;    //定义一个task_struct结构体指针,赋值为NULL
 
static int kthread_test_func(void)   //定义一个内核线程要执行的函数
{
	ENTER();
	while (!kthread_should_stop()) {
		DBG("kthread is running");
		msleep(5000);
	}

	EXIT();
	return 0;
}
 
static __init int kthread_test_init(void)
{
	ENTER();
 
	test_kthread = kthread_run(kthread_test_func, NULL, "kthread-test");  //创建线程kthread-test,并且运行
	if (!test_kthread) {
		ERR("kthread_run fail");
		return -ECHILD;
	}
 
	EXIT();
	return 0;
}
 
static __exit void kthread_test_exit(void)
{
	ENTER();
	if (test_kthread) {
		DBG("kthread_stop");
		kthread_stop(test_kthread); //停止内核线程
		test_kthread = NULL;
	}
   
	EXIT();
}
 
module_init(kthread_test_init);
module_exit(kthread_test_exit);

MODULE_AUTHOR("czd,214241976@qq.com");
MODULE_DESCRIPTION("Device_create Driver");
MODULE_LICENSE("GPL");
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐