内核线程是工作在内核空间的,不属于任何一个进程,可以发生睡眠。内核线程的相关代码在: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。
4. 一个简单的例子:
在模块初始化的时候创建一个内核线程,此内核线程的功能是每隔2秒中打印一条信息。当我们卸载模块的时候,会关闭该内核线程。
#include#include #include #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) MODULE_LICENSE("GPL"); static int demo_thr(void *data){ ENTER(); while (!kthread_should_stop()) { DBG("kthread is running"); msleep_interruptible(2000); } EXIT(); return 0;} static struct task_struct *thr = NULL; static __init int kthread_demo_init(void){ ENTER(); thr = kthread_run(demo_thr, NULL, "kthread-demo"); if (!thr) { ERR("kthread_run fail"); return -ECHILD; } EXIT(); return 0;} static __exit void kthread_demo_exit(void){ ENTER(); if (thr) { DBG("kthread_stop"); kthread_stop(thr); thr = NULL; } EXIT();} module_init(kthread_demo_init);module_exit(kthread_demo_exit);