Linux内核多线程kthread
1.常用API
1.1 kthread_create
用于创建一个内核线程的函数
struct task_struct * kthread_create( int (*threadfn)(void *data),
void *data,
const char namefmt[]);
threadfn :将要去运行的函数实体;
data :传递给将要运行的函数的参数;
namefmt :是说创建的线程的名称;
须知:使用 kthread_create() 接口所创建的线程,并不会马上运行的,而是将其放到了等待队列中去了。如果想要让创建的线程马上运行的话,使用 wake_up_process(struct task_struct *task) 函数将所创建的线程马上唤醒。
1.2 kthread_run
用于创建一个立刻就运行的线程
struct task_struct *kthread_run(int (*kthreadfn)(void *data),
void *data,
const char namefmt[]);
其本质上来说,kthread_run()函数其实是一个宏定义:
#define kthread_run( int (*kthreadfn)(void *data), \
void *data, \
const char namefmt[] ) \
({ \
struct task_struct *kthread = kthread_create( kthread, data, namefmt[]); \
if( !IS_ERR(kthread) ) \
wake_up_process(kthread); \
kthread; \
})
所以 kthread_run()函数的返回值:成功返回线程的地址;
失败返回错误地址;
1.3 kthread_stop
用于创建一个立刻就运行的线程(配合kthread_should_stop使用)
int kthread_stop(struct task_struct *kthread)
返回值:如果这个kthread线程,在通过 ktreadh_create() 函数创建完成以后,就没有通过 wake_up_process()将其唤醒的话,那么此时调用 kthread_stop()函数来停止这个线程的话,就会返回一个 -EINTR的错误码。
1.4 kthread_should_stop
用于判断内核中当前的某个线程是否还在运行的函数(配合kthread_stop使用)
int kthread_should_stop(void)
如果当前的某个线程还在内核中继续运行的话, kthread_should_stop() 函数返回0;
如果当前的某个线程在内核中的某个地方通过使用 kthread_stop(struct task_struct *) 而被停止的话,kthread_should_stop()函数就会立即返回1。
1.5 kthread_bind
将创建的线程绑定到cpu上
void kthread_bind(struct task_struct *p, unsigned int cpu)
这个函数相当于 set_cpus_allowed()
2. 创建内核线程的两种方式
2.1 第一种
最简单的一种
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
static struct task_struct *tsk;
static int thread_function(void *data)
{
int time_count = 0;
do {
printk(KERN_INFO "=====thread_function: %d times=====\n", ++time_count);
msleep(1000);
}while(!kthread_should_stop() && time_count<=30);
return time_count;
}
static int __init kthread_init(void)
{
printk(KERN_INFO "=====kthread_init=====\n");
tsk = kthread_run(thread_function, NULL, "mythread%d", 1);
if (IS_ERR(tsk)) {
printk(KERN_INFO "=====create kthread failed!=====\n");
}
else {
printk(KERN_INFO "=====create ktrhead ok!=====\n");
}
return 0;
}
static void __exit kthread_exit(void)
{
printk(KERN_INFO "=====kthread_exit=====\n");
if (!IS_ERR(tsk)){
int ret = kthread_stop(tsk);
printk(KERN_INFO "=====thread function has run %ds======\n", ret);
}
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL v2");
2.2 第二种
绑定cpu
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
static struct task_struct *tsk;
static int thread_function(void *data)
{
int time_count = 0;
do {
printk(KERN_INFO "=====thread_function: %d times=====\n", ++time_count);
msleep(1000);
}while(!kthread_should_stop() && time_count<=30);
return time_count;
}
static int __init kthread_init(void)
{
printk(KERN_INFO "=====kthread_init=====\n");
tsk = kthread_create(thread_function, NULL, "mythread/%d", 1);
if (IS_ERR(tsk))
{
printk(KERN_INFO "=====create kthread failed!=====\n");
//err = PTR_ERR(ksemd_task);
tsk = NULL;
return -1;
}
else {
/* 绑定线程到指定cpu */
kthread_bind(tsk,1);
/* 运行线程 */
wake_up_process(tsk);
printk(KERN_INFO "=====create ktrhead ok!=====\n");
}
return 0;
}
static void __exit kthread_exit(void)
{
printk(KERN_INFO "=====kthread_exit=====\n");
if (!IS_ERR(tsk)){
int ret = kthread_stop(tsk);
printk(KERN_INFO "=====thread function has run %ds=====\n", ret);
}
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL v2");
3. 注意事项
多个线程用到的全局变量要加volatile,中断处理的全局变量也要加volatile,原因是该变量容易改变,需要慎重读取。