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,如需转载请自行联系原作者

相关文章
|
22天前
|
存储 安全 Linux
探索Linux操作系统的心脏:内核
在这篇文章中,我们将深入探讨Linux操作系统的核心—内核。通过简单易懂的语言和比喻,我们会发现内核是如何像心脏一样为系统提供动力,处理数据,并保持一切顺畅运行。从文件系统的管理到进程调度,再到设备驱动,我们将一探究竟,看看内核是怎样支撑起整个操作系统的大厦。无论你是计算机新手还是资深用户,这篇文章都将带你领略Linux内核的魅力,让你对这台复杂机器的内部运作有一个清晰的认识。
51 3
|
1月前
|
存储 缓存 编译器
Linux kernel memory barriers 【ChatGPT】
Linux kernel memory barriers 【ChatGPT】
44 11
|
1月前
|
缓存 安全 Unix
Linux 内核黑客不可靠指南【ChatGPT】
Linux 内核黑客不可靠指南【ChatGPT】
|
1月前
|
Linux 开发者
Linux内核贡献成熟度模型 【ChatGPT】
Linux内核贡献成熟度模型 【ChatGPT】
|
1月前
|
网络协议 Ubuntu Linux
用Qemu模拟vexpress-a9 (三)--- 实现用u-boot引导Linux内核
用Qemu模拟vexpress-a9 (三)--- 实现用u-boot引导Linux内核
|
1月前
|
Linux
用clang编译Linux内核
用clang编译Linux内核
|
1月前
|
Linux API 调度
关于在Linux内核中使用不同延迟/休眠机制 【ChatGPT】
关于在Linux内核中使用不同延迟/休眠机制 【ChatGPT】
|
2月前
|
存储 监控 Java
Java多线程优化:提高线程池性能的技巧与实践
Java多线程优化:提高线程池性能的技巧与实践
64 1
|
5天前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
13天前
|
Java Spring
spring多线程实现+合理设置最大线程数和核心线程数
本文介绍了手动设置线程池时的最大线程数和核心线程数配置方法,建议根据CPU核数及程序类型(CPU密集型或IO密集型)来合理设定。对于IO密集型,核心线程数设为CPU核数的两倍;CPU密集型则设为CPU核数加一。此外,还讨论了`maxPoolSize`、`keepAliveTime`、`allowCoreThreadTimeout`和`queueCapacity`等参数的设置策略,以确保线程池高效稳定运行。
73 10
spring多线程实现+合理设置最大线程数和核心线程数
下一篇
无影云桌面