转自:http://blog.csdn.net/sharecode/article/details/40076951

Linux内核多线程实现方法 —— kthread_create函数

内核经常需要在后台执行一些操作,这种任务就可以通过内核线程(kernle thread)完成独立运行在内核空间的标准进程。内核线程和普通的进程间的区别在于内核线程没有独立的地址空间,mm指针被设置为NULL;它只在内核空间运行,从来不切换到用户空间去;并且和普通进程一样,可以被调度,也可以被抢占。实际上,内核线程只能由其他内核线程创建,在现有的内核线程中创建一个新的内核线程的方法:

kthread_create:创建线程。
struct task_struct *kthread_create(int (*threadfn)(void *data),void *data,const char *namefmt, ...);//注意,第二个参数data用于向线程传递参数

线程创建后,不会马上运行,而是需要将kthread_create() 返回的task_struct指针传给wake_up_process(),然后通过此函数运行线程。

kthread_run :创建并启动线程的函数,相当于kthread_create +  wake_up_process功能;

struct task_struct *kthread_run(int (*threadfn)(void *data),void *data,const char *namefmt, ...);
kthread_stop:通过发送信号给线程,使之退出。
int kthread_stop(struct task_struct *thread);线程一旦启动起来后,会一直运行,除非该线程主动调用do_exit函数,或者其他的进程调用kthread_stop函数,结束线程的运行。 但如果线程函数正在处理一个非常重要的任务,它不会被中断的。当然如果线程函数永远不返回并且不检查信号,它将永远都不会停止,因此,线程函数必须能让出CPU,以便能运行其他线程。同时线程函数也必须能重新被调度运行。在例子程序中,这是通过schedule_timeout()函数完成的(下面的例子会看到)。

1.      头文件

#include <linux/sched.h>  //wake_up_process()

#include <linux/kthread.h>//kthread_create()、kthread_run()

#include<err.h>             //IS_ERR()、PTR_ERR()

2.      实现

2.1创建线程

在模块初始化时,可以进行线程的创建。使用下面的函数和宏定义:

struct task_struct *kthread_create(int (*threadfn)(void *data),

void *data,

const char namefmt[], ...);

#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;                                                    \

})

例如

static struct task_struct *test_task;

static inttest_init_module(void)    //驱动加载函数

{

int err;

test_task = kthread_create(threadfunc, NULL, "test_task");

if(IS_ERR(test_task)){

printk("Unable to start kernel thread.\n");

err = PTR_ERR(test_task);

test_task =NULL;

return err;

}

wake_up_process(test_task);
       return 0;
   }

module_init(test_init_module);

2.2线程函数

在线程函数里,完成所需的业务逻辑工作。主要框架如下所示:

int threadfunc(void *data){

while(1){

set_current_state(TASK_UNINTERRUPTIBLE);//将当前的状态表示设置为休眠

if(kthread_should_stop()) break;  //解释见“注意”

if(){//条件为真

//进行业务处理

}

else{//条件为假

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

schedule_timeout(HZ);   //
休眠,与set_current_state配合使用,需要计算,这里表示休眠一秒

}

}

return 0;

}

注意:

a. 值得一提的是kthread_should_stop函数,我们需要在开启的线程中嵌入该函数并检查此函数的返回值,否则kthread_stop是不起作用的

b. 休眠有两种相关的状态:TASK_INTERRUPTIBLE and
TASK_UNINTERRUPTIBLE。它们的惟一却不是处于TASK_UNINTERRUPTIBLE状态的进程会忽略信号,而处于TASK_INTERRUPTIBLE状态的进程如果收到信号会被唤醒并处理信号(然后再次进入等待睡眠状态)。两种状态的进程位于同一个等待队列上,等待某些事件,不能够运行。

c.schedule_time(s*HZ)的参数为节拍数,HZ宏每个系统定义不一样,表示每一秒时钟中断数,如在2.6中为1000,2.4中为100, s为秒单位,例如如果要休眠20ms,则schedule_time(0.02*HZ)就可以了。

2.3结束线程

在模块卸载时,可以结束线程的运行。使用下面的函数:

int kthread_stop(structtask_struct *k);

例如:

static void test_cleanup_module(void)

{

if(test_task){

kthread_stop(test_task);

test_task = NULL;

}

}

module_exit(test_cleanup_module);

3.       注意事项

(1)      
在调用kthread_stop函数时,线程函数不能已经运行结束。否则,kthread_stop函数会一直进行等待。在执行kthread_stop的时候,目标线程必须没有退出,否则会Oops。原因很容易理解,当目标线程退出的时候,其对应的task结构也变得无效,kthread_stop引用该无效task结构就会出错。

(2)       线程函数必须能让出CPU,以便能运行其他线程。同时线程函数也必须能重新被调度运行。在例子程序中,这是通过schedule_timeout()函数完成的。

4.性能测试

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

top–p 线程号

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

psaux|grep 线程名

可以用下面的命令显示所有内核线程:
      ps afx

Linux内核多线程实现方法 —— kthread_create函数【转】的更多相关文章

  1. Linux内核源代码分析方法

    Linux内核源代码分析方法   一.内核源代码之我见 Linux内核代码的庞大令不少人"望而生畏",也正由于如此,使得人们对Linux的了解仅处于泛泛的层次.假设想透析Linux ...

  2. linux 内核(驱动)常用函数

    2.4.1 内存申请和释放 include/linux/kernel.h里声明了kmalloc()和kfree().用于在内核模式下申请和释放内存.    void *kmalloc(unsigned ...

  3. Linux内核中常见内存分配函数(三)

    ioremap void * ioremap (unsigned long offset, unsigned long size) ioremap是一种更直接的内存“分配”方式,使用时直接指定物理起始 ...

  4. Linux内核探索之路——关于方法

    转载自:http://blog.chinaunix.net/uid-20608849-id-3014502.html   Linux内核实践之路 -给那些想从Linux内核找点乐趣的人 一个不能回避的 ...

  5. Linux内核中常见内存分配函数【转】

    转自:http://blog.csdn.net/wzhwho/article/details/4996510 1.      原理说明 Linux内核中采用了一种同时适用于32位和64位系统的内存分页 ...

  6. Linux内核堆栈使用方法 进程0和进程1【转】

    转自:http://blog.csdn.net/yihaolovem/article/details/37119971 目录(?)[-] 8 Linux 系统中堆栈的使用方法 81  初始化阶段 82 ...

  7. Linux内核中常见内存分配函数

    1.      原理说明 Linux内核中采用了一种同时适用于32位和64位系统的内存分页模型,对于32位系统来说,两级页表足够用了,而在x86_64系统中,用到了四级页表,如图2-1所示.四级页表分 ...

  8. linux 内核(系统)、函数的理解、宏的程序调试

    1.操作系统 1.1.Linux 内核(系统)的组成的部分: 内核主要有:进程调度.内存管理.虚拟文件系统.网络接口和进程通信五个部分组成. (1)进程调度 进程调度是CPU对多个进程对CPU访问的调 ...

  9. Linux内核中常见内存分配函数(二)

    常用内存分配函数 __get_free_pages unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order) __get_f ...

随机推荐

  1. 使用JMeter录制Web应用测试脚本

    环境 操作系统:Windows 7 工具:JMeter.Badboy 1. 使用代理录制Web性能测试脚本 使用代理录制脚本来创建测试计划无疑是一个简便的方法,代理所要完成的工作就是录制发往服务器的请 ...

  2. lxs1314 is not in the sudoers file. This incident will be reported.

    虚拟机下面  普通用户用sudo执行命令时报"xxx is not in the sudoers file.This incident will be reported"错误,解决 ...

  3. UVA11736_Debugging RAM

    题目绝对够水,我就不详细说明了. 直接上代码吧.只是提示一下要用 unsigned long long. (不知道我不用字典树为什么会超时,肿么搞的) #include <iostream> ...

  4. 题解 P1628 【合并序列】

    看到这个题,小金羊第一秒的反应就是: 优先队列可解! 看到楼上某同学一个个比较, find()函数是时候现身了! string//类型库 //find具体用法可以自行百度 //这里仅说这里的用法(逃) ...

  5. Mysql局域网访问授权

    如果允许用户myuser从ip为192.168.1.1的主机连接到mysql服务器,并使用password作为密码 GRANT ALL PRIVILEGES ON *.* TO 'myuser'@'1 ...

  6. python打造12306余票实时监控

    # encoding=utf-8from Tkinter import *from ScrolledText import ScrolledTextimport urllib2import jsoni ...

  7. C 位段,位域

    百度百科解释的很好,地址如下: http://baike.baidu.com/link?url=9yb5izRj6S1TzsN--EVexN7BAEzSn3jGctSgcoLTwVfaCXmtfMj3 ...

  8. Spring切面之一

    为什么要使用AOP,在编写程序的时候,除了不必关心依赖的组件如何实现,在实际开发过程中,还需要将程序中涉及的公共问题集中解决.AOP是Aspect-Oriented Programming的简称,意思 ...

  9. 洛谷P1290 欧几里得的游戏

    题目描述 欧几里德的两个后代Stan和Ollie正在玩一种数字游戏,这个游戏是他们的祖先欧几里德发明的.给定两个正整数M和N,从Stan开始,从其中较大的一个数,减去较小的数的正整数倍,当然,得到的数 ...

  10. 洛谷P1078 文化之旅

    P1078 文化之旅 1.1K通过 3.6K提交 题目提供者洛谷OnlineJudge 标签NOIp普及组2012 难度普及+/提高 时空限制1s / 128MB 提交  讨论  题解 最新讨论更多讨 ...