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

简介:

启发主要来自于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)即可。

 






本文转自五岳博客园博客,原文链接:www.cnblogs.com/wuyuegb2312/archive/2012/06/28/2568411.html,如需转载请自行联系原作者

目录
相关文章
|
6月前
|
消息中间件 存储 算法
【软件设计师备考 专题 】操作系统的内核(中断控制)、进程、线程概念
【软件设计师备考 专题 】操作系统的内核(中断控制)、进程、线程概念
190 0
|
6月前
|
Go 调度
go-issues#14592 runtime: let idle OS threads exit 内核线程暴增与线程回收问题
go-issues#14592 runtime: let idle OS threads exit 内核线程暴增与线程回收问题
45 0
|
6月前
|
Linux API 调度
xenomai内核解析-xenomai实时线程创建流程
本文介绍了linux硬实时操作系统xenomai pthread_creta()接口的底层实现原理,解释了如何在双内核间创建和调度一个xenomai任务。本文是基于源代码的分析,提供了详细的流程和注释,同时给出了结论部分,方便读者快速了解核心内容。
177 0
xenomai内核解析-xenomai实时线程创建流程
|
6月前
|
存储 算法 Linux
【Linux】线程的内核级理解&&详谈页表以及虚拟地址到物理地址之间的转化
【Linux】线程的内核级理解&&详谈页表以及虚拟地址到物理地址之间的转化
|
6月前
|
Linux
Linux进程与线程的内核实现
task_struct称为进程描述符结构,该结构定义在文件中。进程描述符中包含一个具体进程的所有信息 进程描述符中包含的数据能完整地描述一个正在执行的程序:它打开的文件,进程的地址空间,挂起的信号,进程的状态等
69 0
Linux进程与线程的内核实现
|
6月前
|
存储 算法 Linux
一起聊聊内核中的线程:操作函数、进程状态、task_struct、举个例子、
一起聊聊内核中的线程:操作函数、进程状态、task_struct、举个例子、
227 0
|
6月前
|
存储 安全 Linux
Linux中断(tasklet,工作队列,内核线程的使用)
Linux中断(tasklet,工作队列,内核线程的使用)
129 0
|
网络协议 安全 API
驱动开发:内核远程线程实现DLL注入
在笔者上一篇文章`《内核RIP劫持实现DLL注入》`介绍了通过劫持RIP指针控制程序执行流实现插入DLL的目的,本章将继续探索全新的注入方式,通过`NtCreateThreadEx`这个内核函数实现注入DLL的目的,需要注意的是该函数在微软系统中未被导出使用时需要首先得到该函数的入口地址,`NtCreateThreadEx`函数最终会调用`ZwCreateThread`,本章在寻找函数的方式上有所不同,前一章通过内存定位的方法得到所需地址,本章则是通过解析导出表实现。
4946 0
|
Shell
驱动开发:内核ShellCode线程注入
还记得`《驱动开发:内核LoadLibrary实现DLL注入》`中所使用的注入技术吗,我们通过`RtlCreateUserThread`函数调用实现了注入DLL到应用层并执行,本章将继续探索一个简单的问题,如何注入`ShellCode`代码实现反弹Shell,这里需要注意一般情况下`RtlCreateUserThread`需要传入两个最重要的参数,一个是`StartAddress`开始执行的内存块,另一个是`StartParameter`传入内存块的变量列表,而如果将`StartParameter`地址填充为`NULL`则表明不传递任何参数,也就是只在线程中执行`ShellCode`代码,利用
381 1
|
SQL 监控 druid
MySQL线程池导致的延时卡顿排查
## 问题描述 简单小表的主键点查SQL,单条执行很快,但是放在业务端,有时快有时慢,取了一条慢sql,在MySQL侧查看,执行时间很短。 通过Tomcat业务端监控有显示慢SQL,取slow.log里显示有12秒执行时间的SQL,但是这次12秒的执行在MySQL上记录下来的执行时间都不到1ms。 所在节点的tsar监控没有异常,Tomcat manager监控上没有fgc,Tomcat实
1893 0
MySQL线程池导致的延时卡顿排查

热门文章

最新文章

相关实验场景

更多