Linux Kernel Development----内核线程

简介:

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

实际上,内核线程只能由其他内核线程创建,在现有的内核线程中创建一个新的内核线程的方法:

1. kernel_thread      

int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);        

kernel_thread通过do_fork实现:do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL)。    

需要注意的是,在执行函数fn里面必须用daemonize释放资源并挂到init下,还需要用completion等待这一过程的完成。

2. kthread_run

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

    创建内核线程并启动。    

3. kthread_create

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

  int wake_up_process(struct task_struct *p);

    kthread_create创建一个新的内核线程,但线程是停止的,需要用wake_up_process启动它

使用示例

复制代码
 1 #include <linux/kthread.h>
 2 #include <linux/module.h>
 3 
 4 #ifndef SLEEP_MILLI_SEC
 5 #define SLEEP_MILLI_SEC(nMilliSec)\
 6     do { \
 7     long timeout = (nMilliSec) * HZ / 1000; \
 8     while(timeout > 0) \
 9     { \
10     __set_current_state(TASK_INTERRUPTIBLE); \
11     timeout = schedule_timeout(timeout); \
12     } \
13     }while(0);
14 #endif
15 
16 static struct task_struct * MyThread = NULL;
17 
18 static int MyPrintk(void *data)
19 {
20     char *mydata = kmalloc(strlen(data)+1,GFP_KERNEL);
21     memset(mydata,'\0',strlen(data)+1);
22     strncpy(mydata,data,strlen(data));
23     while(!kthread_should_stop())
24     {
25         SLEEP_MILLI_SEC(1000);
26         printk("%s\n",mydata);
27     }
28     kfree(mydata);
29     return 0;
30 }
31 
32 static int __init init_kthread(void)
33 {
34     MyThread = kthread_run(MyPrintk,"hello world","mythread");
35     return 0;
36 }
37 
38 static void __exit exit_kthread(void)
39 {
40     if(MyThread)
41     {
42         printk("stop MyThread\n");
43         kthread_stop(MyThread);
44     }
45 }
46 
47 module_init(init_kthread);
48 module_exit(exit_kthread);
49 MODULE_LICENSE("Dual BSD/GPL");
复制代码

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

实际上,内核线程只能由其他内核线程创建,在现有的内核线程中创建一个新的内核线程的方法:

1. kernel_thread      

int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);        

kernel_thread通过do_fork实现:do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL)。    

需要注意的是,在执行函数fn里面必须用daemonize释放资源并挂到init下,还需要用completion等待这一过程的完成。

2. kthread_run

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

    创建内核线程并启动。    

3. kthread_create

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

  int wake_up_process(struct task_struct *p);

    kthread_create创建一个新的内核线程,但线程是停止的,需要用wake_up_process启动它

使用示例

复制代码
 1 #include <linux/kthread.h>
 2 #include <linux/module.h>
 3 
 4 #ifndef SLEEP_MILLI_SEC
 5 #define SLEEP_MILLI_SEC(nMilliSec)\
 6     do { \
 7     long timeout = (nMilliSec) * HZ / 1000; \
 8     while(timeout > 0) \
 9     { \
10     __set_current_state(TASK_INTERRUPTIBLE); \
11     timeout = schedule_timeout(timeout); \
12     } \
13     }while(0);
14 #endif
15 
16 static struct task_struct * MyThread = NULL;
17 
18 static int MyPrintk(void *data)
19 {
20     char *mydata = kmalloc(strlen(data)+1,GFP_KERNEL);
21     memset(mydata,'\0',strlen(data)+1);
22     strncpy(mydata,data,strlen(data));
23     while(!kthread_should_stop())
24     {
25         SLEEP_MILLI_SEC(1000);
26         printk("%s\n",mydata);
27     }
28     kfree(mydata);
29     return 0;
30 }
31 
32 static int __init init_kthread(void)
33 {
34     MyThread = kthread_run(MyPrintk,"hello world","mythread");
35     return 0;
36 }
37 
38 static void __exit exit_kthread(void)
39 {
40     if(MyThread)
41     {
42         printk("stop MyThread\n");
43         kthread_stop(MyThread);
44     }
45 }
46 
47 module_init(init_kthread);
48 module_exit(exit_kthread);
49 MODULE_LICENSE("Dual BSD/GPL");
复制代码

本文转自feisky博客园博客,原文链接:http://www.cnblogs.com/feisky/archive/2013/03/05/2945187.html,如需转载请自行联系原作者

相关文章
|
7月前
|
存储 Linux API
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
在计算机系统的底层架构中,操作系统肩负着资源管理与任务调度的重任。当我们启动各类应用程序时,其背后复杂的运作机制便悄然展开。程序,作为静态的指令集合,如何在系统中实现动态执行?本文带你一探究竟!
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
|
2月前
|
监控 Linux 开发者
理解Linux操作系统内核中物理设备驱动(phy driver)的功能。
综合来看,物理设备驱动在Linux系统中的作用是至关重要的,它通过与硬件设备的紧密配合,为上层应用提供稳定可靠的通信基础设施。开发一款优秀的物理设备驱动需要开发者具备深厚的硬件知识、熟练的编程技能以及对Linux内核架构的深入理解,以确保驱动程序能在不同的硬件平台和网络条件下都能提供最优的性能。
137 0
|
5月前
|
并行计算 Linux
Linux内核中的线程和进程实现详解
了解进程和线程如何工作,可以帮助我们更好地编写程序,充分利用多核CPU,实现并行计算,提高系统的响应速度和计算效能。记住,适当平衡进程和线程的使用,既要拥有独立空间的'兄弟',也需要在'家庭'中分享和并行的成员。对于这个世界,现在,你应该有一个全新的认识。
241 67
|
3月前
|
存储 负载均衡 算法
Linux2.6内核进程调度队列
本篇文章是Linux进程系列中的最后一篇文章,本来是想放在上一篇文章的结尾的,但是想了想还是单独写一篇文章吧,虽然说这部分内容是比较难的,所有一般来说是简单的提及带过的,但是为了让大家对进程有更深的理解与认识,还是看了一些别人的文章,然后学习了学习,然后对此做了总结,尽可能详细的介绍明白。最后推荐一篇文章Linux的进程优先级 NI 和 PR - 简书。
106 0
|
5月前
|
存储 Linux
Linux内核中的current机制解析
总的来说,current机制是Linux内核中进程管理的基础,它通过获取当前进程的task_struct结构的地址,可以方便地获取和修改进程的信息。这个机制在内核中的使用非常广泛,对于理解Linux内核的工作原理有着重要的意义。
228 11
|
6月前
|
自然语言处理 监控 Linux
Linux 内核源码分析---proc 文件系统
`proc`文件系统是Linux内核中一个灵活而强大的工具,提供了一个与内核数据结构交互的接口。通过本文的分析,我们深入探讨了 `proc`文件系统的实现原理,包括其初始化、文件的创建与操作、动态内容生成等方面。通过对这些内容的理解,开发者可以更好地利用 `proc`文件系统来监控和调试内核,同时也为系统管理提供了便利的工具。
261 16
|
7月前
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
通过本文,您可以了解如何在业务线程中注册和处理Linux信号。正确处理信号可以提高程序的健壮性和稳定性。希望这些内容能帮助您更好地理解和应用Linux信号处理机制。
128 26
|
7月前
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
本文详细介绍了如何在Linux中通过在业务线程中注册和处理信号。我们讨论了信号的基本概念,并通过完整的代码示例展示了在业务线程中注册和处理信号的方法。通过正确地使用信号处理机制,可以提高程序的健壮性和响应能力。希望本文能帮助您更好地理解和应用Linux信号处理,提高开发效率和代码质量。
133 17
|
11月前
|
安全 Linux
Linux线程(十一)线程互斥锁-条件变量详解
Linux线程(十一)线程互斥锁-条件变量详解