Linux内核多线程kthread

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,原因是该变量容易改变,需要慎重读取。

猜你喜欢

转载自blog.csdn.net/wyy626562203/article/details/81232932