内核线程的创建、使用和退出;关于延时宏的补充说明

  启发主要来自于http://blog.csdn.net/newnewman80/article/details/7050090,基本是根据自己的习惯重组的。

相关函数:

kthread_create():创建内核线程

struct task_struct *kthread_create(int (*threadfn)(void *data), void *data, const char namefmt[], ...);  

kernel thread可以用kernel_thread创建,但是在执行函数里面必须用daemonize释放资源并挂到init下,还需要用completion等待这一过程的完成。为了简化操作,定义了kthread_create。
线程创建后,不会马上运行,而是需要将kthread_create() 返回的task_struct指针传给wake_up_process(),然后通过此函数运行线程。

 

kthread_run():创建并启动线程的函数。

struct task_struct *kthread_run(int (*threadfn)(void *data),void *data,const char *namefmt, ...);

它实际上是个宏,由kthread_create()和wake_up_process()组成。 

#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_stop()通过发送信号给线程,使之退出。

int kthread_stop(struct task_struct *thread);

线程一旦启动起来后,会一直运行,除非该线程主动调用do_exit函数,或者其他的进程调用kthread_stop函数,结束线程的运行。
但如果线程函数正在处理一个非常重要的任务,它不会被中断的。当然如果线程函数永远不返回并且不检查信号,它将永远都不会停止。

同时,在调用kthread_stop函数时,线程函数不能已经运行结束。否则,kthread_stop函数会一直进行等待。

 

内核线程的一般框架

int threadfunc(void *data){

        …

        while(1){

               set_current_state(TASK_UNINTERRUPTIBLE);

               if(kthread_should_stop()) break;

               if(){//条件为真

                      //进行业务处理

               }

               else{//条件为假

                      //让出CPU运行其他线程,并在指定的时间内重新被调度

                      schedule_timeout(HZ);

               }

        }

        …

        return 0;

}

 

线程相关测试命令

  可以使用top命令来查看线程(包括内核线程)的CPU利用率。命令如下:

    top –p 线程号

  可以使用下面命令来查找线程号:

    ps aux|grep 线程名

 

示例程序:使用模块加载内核线程,实现每1s在内核中打印字符。

(makefile略去,和以前一篇博文一样的写法。)

 

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>   //wake_up_process()
#include <linux/kthread.h> //kthread_create(),kthread_run()
#include <linux/err.h> //IS_ERR(),PTR_ERR()
#ifndef SLEEP_MILLI_SEC
#define SLEEP_MILLI_SEC(nMilliSec)\
do { \
long timeout = (nMilliSec) * HZ / 1000; \
while(timeout > 0) \
{ \
timeout = schedule_timeout(timeout); \
} \
}while(0);
#endif

static struct task_struct *my_task = NULL;

static int my_kthread(void *data)  
{  
    char *mydata = kmalloc(strlen(data)+1,GFP_KERNEL);
    memset(mydata,'\0',strlen(data)+1);
    strncpy(mydata,data,strlen(data));
    while(!kthread_should_stop())
    {
        SLEEP_MILLI_SEC(1000);
        printk("%s\n",mydata);
    }
    kfree(mydata);
    return 0;
}  

static int __init kernel_thread_init(void)
{
    int err;
    printk(KERN_ALERT "Kernel thread initalizing...\n");
    my_task = kthread_create(my_kthread,"hello world","mythread");
    if(IS_ERR(my_task)){
        printk("Unable to start kernel thread./n");
        err = PTR_ERR(my_task);
        my_task = NULL;
        return err;
    }
    wake_up_process(my_task);
    return 0;
}
static void __exit kernel_thread_exit(void) { if(my_task){ printk(KERN_ALERT "Cancel this kernel thread.\n"); kthread_stop(my_task); printk(KERN_ALERT "Canceled.\n"); } } module_init(kernel_thread_init); module_exit(kernel_thread_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("anonymous");

 

补充说明:

  这个延时宏在一些情况下会造成内核线程CPU占用率过高的情况。根据对schedule_timeout()源码的分析,它只是周期使线程成为TASK_RUNNING状态,这个线程并没有真正的睡眠。解决办法:在while循环中的起始处加入set_current_state(TASK_INTERRUPTIBLE)即可。

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
内核线程是在Linux内核层面运行的线程,它们与用户空间的线程有所不同。在内核中,我们可以使用互斥锁进行多个内核线程之间的同步。 下面是一个简单的内核模块示例,它创建了两个内核线程,这两个线程会轮流访问一个共享的计数器,并使用互斥锁进行同步: ```c #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/kthread.h> #include <linux/mutex.h> static struct task_struct *thread1, *thread2; static int counter = 0; static DEFINE_MUTEX(mutex); int thread_func(void *data) { int i; for (i = 0; i < 5; i++) { mutex_lock(&mutex); counter++; printk(KERN_INFO "Counter incremented by %d\n", counter); mutex_unlock(&mutex); msleep(1000); } return 0; } static int __init my_module_init(void) { mutex_init(&mutex); thread1 = kthread_create(thread_func, NULL, "my_thread1"); if (IS_ERR(thread1)) { printk(KERN_INFO "Failed to create thread1\n"); return PTR_ERR(thread1); } wake_up_process(thread1); thread2 = kthread_create(thread_func, NULL, "my_thread2"); if (IS_ERR(thread2)) { printk(KERN_INFO "Failed to create thread2\n"); kthread_stop(thread1); return PTR_ERR(thread2); } wake_up_process(thread2); return 0; } static void __exit my_module_exit(void) { kthread_stop(thread1); kthread_stop(thread2); mutex_destroy(&mutex); } module_init(my_module_init); module_exit(my_module_exit); ``` 在上面的代码中,我们首先定义了一个共享的计数器`counter`,然后创建了两个内核线程`thread1`和`thread2`,这两个线程会轮流访问计数器,并使用互斥锁`mutex`进行同步。 在线程函数`thread_func`中,我们使用`mutex_lock`函数对互斥锁进行加锁操作,然后对计数器进行加1操作,并打印出新的计数器值。在操作完成后,我们使用`mutex_unlock`函数对互斥锁进行解锁操作。这样可以保证在任何时刻,只有一个线程可以访问计数器。 在模块的初始化函数`my_module_init`中,我们首先使用`mutex_init`函数对互斥锁进行初始化。然后创建两个内核线程,并使用`wake_up_process`函数启动它们。在模块的退出函数`my_module_exit`中,我们使用`kthread_stop`函数停止内核线程,并使用`mutex_destroy`函数销毁互斥锁。 需要注意的是,在内核中,我们可以使用`mutex_lock`和`mutex_unlock`函数对内核互斥锁进行加锁和解锁操作,这些函数与用户空间的`pthread_mutex_lock`和`pthread_mutex_unlock`函数使用方法类似,但是函数名略有不同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值