转自: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

【作者】张昺华
【出处】http://www.cnblogs.com/sky-heaven/
【博客园】 http://www.cnblogs.com/sky-heaven/
【新浪博客】 http://blog.sina.com.cn/u/2049150530
【知乎】 http://www.zhihu.com/people/zhang-bing-hua
【我的作品---旋转倒立摆】 http://v.youku.com/v_show/id_XODM5NDAzNjQw.html?spm=a2hzp.8253869.0.0&from=y1.7-2
【我的作品---自平衡自动循迹车】 http://v.youku.com/v_show/id_XODM5MzYyNTIw.html?spm=a2hzp.8253869.0.0&from=y1.7-2
【新浪微博】 张昺华--sky
【twitter】 @sky2030_
【facebook】 张昺华 zhangbinghua
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.

Linux内核多线程实现方法 —— kthread_create函数【转】相关推荐

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

          Linux内核多线程实现方法 -- kthread_create函数 内核经常需要在后台执行一些操作,这种任务就可以通过内核线程(kernle thread)完成独立运行在内核空间的标准进 ...

  2. Linux内核源代码获取方法

    Linux内核源代码获取方法 什么叫Linux 什么叫Linux内核 Linux内核源代码的获取 什么叫Linux? Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UN ...

  3. 【Linux 内核 内存管理】Linux 内核内存布局 ③ ( Linux 内核 动态分配内存 系统接口函数 | 统计输出 vmalloc 分配的内存 )

    文章目录 一.Linux 内核 动态分配内存 系统接口函数 二.统计输出 vmalloc 分配的内存 一.Linux 内核 动态分配内存 系统接口函数 Linux 内核 " 动态分配内存 & ...

  4. Android驱动(1)---Ubuntu中为Android系统上编写Linux内核驱动程序实现方法

    Ubuntu中为Android系统上编写Linux内核驱动程序实现方法 本文主要介绍在Ubuntu 上为Android系统编写Linux内核驱动程序, 这里对编写驱动程序做了详细的说明,对研究Andr ...

  5. Linux内核的编译方法及如何往内核中增加程序

    2019独角兽企业重金招聘Python工程师标准>>> ARM Linux的系统调用实现原理是采用swi软中断从用户(usr)模式陷入管理模式(svc). 内核空间和用户空间这两个名 ...

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

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

  7. Linux内核中64位除法函数do_div

    使用asm/div64.h中宏do_div #include <asm/div64.h> unsigned long long x,y,result; unsigned long mod; ...

  8. linux内核提供的内存操作函数

    1.kmalloc()/kfree()         static __always_inline void *kmalloc(size_t size, gfp_t flags)         内 ...

  9. 【Linux 内核】调度器 ⑥ ( task_woken 函数 | set_cpus_allowed 函数 | rq_online 函数 | rq_offline 函数 )

    文章目录 一.task_woken 函数 ( 唤醒阻塞进程 ) 二.set_cpus_allowed 函数 ( 修改进程在 CPU 中的亲和力 ) 三.rq_online 函数 ( 启动执行队列 ) ...

  10. linux查看tcl版本_查看Linux内核版本的方法有几个?你也是这样操作吗?

    请关注本头条号,每天坚持更新原创干货技术文章.如需学习视频,请在微信搜索公众号"智传网优"直接开始自助视频学习 1. 前言 内核是操作系统的核心组件. 它管理系统的资源,是计算机硬 ...

最新文章

  1. LinkedBlockingQueue应用实例
  2. 【洛谷P1697】货车运输
  3. 阿里云前端周刊 - 第 26 期
  4. win服务器文件夹权限设置密码,win服务器 文件夹权限设置
  5. Spring的线程安全
  6. 3年了,我依旧单身,而微信小程序已经普及了
  7. 【项目3-2】多肉植物网站
  8. MAC编译jogl/gluegen很顺利
  9. STM32通过BC28用mqtt协议连接onenet及simulate-device的使用
  10. 网课题库接口教程(免费)
  11. Mac Air USB接口 失效/不起作用 的修复方式
  12. 转行python算法_转:Python:SMOTE算法
  13. CCF CSP 201903-1 小中大
  14. ValueError:only one element tensors can be converted to Python scalars解决办法
  15. 历史上最有名的五句农民起义军口号
  16. 【opencv-python】 HSV抠图-智能车拟合道路边界和中线
  17. 学mysql后的收获_数据库课程学习的收获和心得体会
  18. QQmlContext设置上下文
  19. js第8章事件案例:获取触发事件的元素,阻止事件冒泡和默认行为的实现、缓动的小球、图片放大特效、按Enter键切换
  20. c语言若输入错误的是,C语言新人常见问题与错误

热门文章

  1. maven中GroupID 和ArtifactID怎么写
  2. JSON.parse和eval的区别
  3. 最小高度100%页脚保持在底部的布局方法
  4. Sound Studio for Mac - 音频编辑处理工具
  5. Omni Converter全能转换器安装教程
  6. docker下的Mysql镜像的使用方法
  7. SQL--数据--基本操作
  8. combobox 属性、事件、方法
  9. Streaming源码解读 updateStateByKey-1
  10. Thread 中的 中断