linux驱动模块中可以用kernel_thread(),kthread_create()/kthread_run()两种方式创建内核线程,另外还可以用第三方库(如pthread,除此之外还有其他的第三方库),在驱动模块中创建线程(pthread也可以用在用户空间)
一、kernel_thread
kernel_thread()声明在include/linux/sched.h里面:
extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
参数说明:
fn:线程函数地址
arg:线程函数的形参,没有,可以是NULL
flags:标志,一般用CLONE_KERNEL(定义在linux/sched.h中,注意有的版本中,没用定义),其他标志及含义见uapi/linux/sched.h中。
返回值:返回线程ID值。
注意:kernel_thread()由于没有用EXPORT_SYMBOL导出来,所以用kernel_thread()这能用在和内核一起编译的驱动代码中,如用在ubuntu系统上,不随内核一起编译,单独的驱动程序时,可以编译过,但是用insmod加载驱动模块时,会报未知符号错误”Unknown symbol in module”,而不能加载。
kernel_thread()用法例子:
#include "linux/module.h"
#include "linux/moduleparam.h"
#include "linux/init.h"
#include "linux/kmod.h"
#include "linux/sched.h"
#include "linux/delay.h"
MODULE_AUTHOR("zimu");
MODULE_LICENSE("GPL");
#define CLONE_KERNEL (CLONE_FS | CLONE_FILES | CLONE_SIGHAND)
int my_kernel_thread(void *arg)
int n = 0; while(1) printk("%s: %d\n",__func__,n++); ssleep(3); return 0;
static int __init practiceCall(void)
printk("%s:\n",__func__); kernel_thread(my_kernel_thread,NULL,CLONE_KERNEL); return 0;
static void __exit practiceCallExit(void)
printk("%s:\n",__func__);
module_init(practiceCall);
module_exit(practiceCallExit);
这个例子运行,会每隔3秒n加1,并打印出来。
二、kthread_create():
kthread_create()定义在include/linux/kthread.h里面,下如:
__printf(4, 5)
struct task_struct *kthread_create_on_node(
int (*threadfn)(void *data), void *data,int node, const char namefmt[], ...);
* kthread_create - create a kthread on the current node
* @threadfn: the function to run in the thread
* @data: data pointer for @threadfn()
* @namefmt: printf-style format string for the thread name
* @...: arguments for @namefmt.
* This macro will create a kthread on the current node, leaving it in
* the stopped state. This is just a helper for kthread_create_on_node();
* see the documentation there for more details.
#define kthread_create(threadfn, data, namefmt, arg...) kthread_create_on_node(threadfn,
注意:kthread_create()创建后,线程没有立即运行,需要将返回的值,即线程指针(struct task_struct *),作为参数传入到wake_up_process()唤起线程运行。
用法例子:
#include "linux/module.h"
#include "linux/moduleparam.h"
#include "linux/init.h"
#include "linux/kmod.h"
#include "linux/sched.h"
#include "linux/delay.h"
#include "linux/kthread.h"
MODULE_AUTHOR("zimu");
MODULE_LICENSE("GPL");
#define CLONE_KERNEL (CLONE_FS | CLONE_FILES | CLONE_SIGHAND)
strcut task_struct *practice_task_p = NULL;
int my_kernel_thread(void *arg)
int n = 0; while(1) printk("%s: %d\n",__func__,n++); ssleep(3); if(kthread_should_stop()) 这个例子运行,每隔3秒n加1,并输出,当退出模块时,调用了kthread_stop()函数,当my_kernel_kernel()运行到if(kthread_should_stop())时,条件为真,退出while(1){…}线程退出停止。 注意:在编写线程循环体时,一般都要加入kthread_should_stop(),如果不加,调用kthread_stop()是没有效果的,也会导致模块退出后,线程仍然还在运行。
三、kthread_run():
kthread_run()声明在include/linux/kthread.h里面,如下:
* 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, ...) 注意:kernel_thread()的参数fn,以及kthread_create()/kthread_run()的参数threadfn即使是一样的函数,只要创建的线程不一样(线程名字不一样),那么fn,threadfn函数在不同的线程里面,运行的空间地址是不一样的。
四、线程的park状态:
park翻译成中文:停止,停车场等
线程的stop(kthread_stop())状态,是指线程终止,线程的生命周期结束。 线程的park状态(kthread_park()),是指线程暂时停止(可以理解就是挂起),当执行换线(kthread_unpark())后,线程从挂起状态唤醒,接着运行。
用法例子:
#include "linux/module.h"
#include "linux/moduleparam.h"
#include "linux/init.h"
#include "linux/kmod.h"
#include "linux/sched.h"
#include "linux/delay.h"
#include "linux/kthread.h"
MODULE_AUTHOR("zimu");
MODULE_LICENSE("GPL");
#define CLONE_KERNEL (CLONE_FS | CLONE_FILES | CLONE_SIGHAND)
int my_kernel_thread(void *arg)
int n = 0; while(1) printk("%s: %d\n",__func__,n++); ssleep(3); if(kthread_should_park()) kthread_parkme(); if(kthread_should_stop()) 当在其他某个地方,调用kthread_park(practice_task_p)后,线程将在kthread_parkme()处挂起睡眠,直到其他某个地方执行了kthread_unpark(practice_task_p)后,线程才被唤起,继续执行。
五、线程的freeze状态:
进程(线程)冻结技术(freezing of tasks)是指在系统hibernate或者suspend的时候,将用户进程和部分内核线程置于“可控”的暂停状态。
当系统进入hibernate或者suspend的时候,线程如果要响应,那么线程需要使用相应接口将线程冻结。
如下接口都声明在include/linux/freezer.h里面
static inline bool try_to_freeze(void);
static inline bool freezing(struct task_struct *p);
声明在include/linux/kthread.h:
bool kthread_freezable_should_stop(bool *was_frozen);
两种用法:
int my_kernel_thread(void *arg)
int n = 0; bool free; while(1) printk("%s: %d\n",__func__,n++); ssleep(3); if(kthread_freezable_should_stop()) break; return 0; kthread_freezable_should_stop如果系统进入hibernate或者suspend,将当前线程挂起,并置位PF_FROZEN标志,调用schedule()放弃CPU控制全,直到系统退出hibernate或者suspend,或者其他唤起,kthread_freezable_should_stop才会返回,否则将一直不返回。 kthread_freezable_should_stop为了安全,返回的是线程是否需要退出真值(true,false),返回的was_frozen值,true表示线程是从冻结后唤醒退出的,false表示没有被冻结。
int my_kernel_thread(void *arg)
int n = 0; bool free; while(1) printk("%s: %d\n",__func__,n++); ssleep(3); if(freezing(current)) try_to_freeze(); if(kthread_should_stop())
freezing()判断系统是否进入冻结,ture冻结,false没有冻结。
try_to_freeze()将当前线程冻结,冻结后将不会返回,直到解冻,或者其他唤起,否则一直不返回。
线程是否要响应系统的冻结状态,需要根据情况,看系统冻结后,驱动模块是否需要运行。
六、kthread_bind():
kthread_bind()声明在include/linux/kthread.h,如下:
void kthread_bind(struct task_struct *k, unsigned int cpu);
功能:将线程和CPU绑定,这个线程只在绑定的CPU上运行,在多核CPU上用
参数说明:
k:线程结构体指针
cpu:要绑定的CPU号
七、第三方线程库pthread:
见其它地方,待写完后,地址再放到这里。

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑