线程分类:内核线程、用户线程(指不须要内核支持而彻底创建在用户空间的线程库,这种线程效率高,因为Linux内核没有轻量级进程(线程)的概念,所以不能独立的对用户线程进行调度,而是由一个线程运行库来组织线程的调度)和轻量级线程(内核线程的高级抽象,大多数操做涉及到系统调用,效率不高)。html
传统的Unix系统把一些重要的任务委托给周期性的执行进程,这些任务包括刷新磁盘高速缓存,交换出不用的页框,维护网络链接等。这些线程只运行在内核态(普通进程既能够运行在内核态,也能够运行在用户态),内核线程只运行在内核态,因此只使用大于PAGE_OFFSET的线性地址空间。现代操做系统把它们的函数委托给内核线程,内核线程不受没必要要的用户态上下文拖累。内核线程的使用是廉价的,惟一使用的资源就是内核栈和上下文切换时保存寄存器的空间。linux
内核线程(thread)或叫守护进程(daemon)缓存
建立内核线程网络
kernel_thread()函数建立一个新的内核线程,它接受的参数:所要执行的内核函数地址(fn)、要传递给函数的参数(arg)、一组clone标志(flags)。该函数的本质上是调用数据结构
do_fork(flags|CLONE_VM|CLONE_UNTRACED),0,pregs,0,NULL,NULL); //pregs表示内核栈的地址 //CLONE_VM;避免复制进程页表 pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { struct pt_regs regs; memset(®s, 0, sizeof(regs)); regs.ARM_r1 = (unsigned long)arg; regs.ARM_r2 = (unsigned long)fn; regs.ARM_r3 = (unsigned long)do_exit; regs.ARM_pc = (unsigned long)kernel_thread_helper; regs.ARM_cpsr = SVC_MODE; return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL,NULL); }
进程0
全部进程的祖先叫作进程0,idle进程或由于历史的缘由叫作swapper 进程。它是在linux的初始化阶段从无到有的建立的一个内核线程。这个祖先进程使用静态分配的数据结构。app
在多处理器系统中,每一个CPU都有一个进程0,只要打开机器电源,计算机的BIOS就启动一个CPU,同时禁用其余CPU。运行的CPU 0上的swapper进程初初始化内核数据结构,而后激活其余的CPU,而且使用copy_process()函数建立另外的swapper进程,把0 传递给新建立的swapper进程做为他们进程的PID。函数
进程1 ui
由进程0建立的内核线程执行init()函数,init() 一次完成内核的初始化。init()调用execve系统调用装入可执行程序init ,结果,init 内核线程变成一个普通的进程,且拥有本身的每一个进程内核数据结构。在系统关闭以前,init 进程一直存活,由于它建立和监控在操做系统外层执行的全部进程的活动。atom
其余内核线程spa
events 处理内核事件 不少软硬件事件(好比断电,文件变动)被转换为events,并分发给对相应事件感兴趣的线程进行响应
ksoftirqd :处理软中断 硬件中断处理每每须要关中断,而这个时间不能太长,不然会丢失新的中断。因此中断处理的很大一部分工做移出,转给不辞辛苦的ksoftirqd在中断以外进行处理。好比一个网络包,从网卡里面取出这个过程可能须要关中断,可是TCP/IP协议处理就没必要关中断了
kblockd :管理磁盘块读写
kjournald: Ext3文件系统的日志管理 一般每一个 _已mount_ 的 Ext3分区会有一个 kjournald看管,各分区的日志是独立
Pdflush: dirty内存页面的回写 太多dirty的页面意味着风险,好比故障时候的内容丢失,以及对突发的大量物理内存请求的响应(大量回写会致使糟糕的响应时间)
kswapd :内存回收 确保系统空闲物理内存的数量在一个合适的范围
aio :代替用户进程管理io 用以支持用户态的AIO
驱动中应用内核线程
#include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/param.h> #include <linux/jiffies.h> #include <asm/system.h> #include <asm/processor.h> #include <asm/signal.h> static pid_t thread_id; staticDECLARE_COMPLETION(exit_completion); static atomic_t time_to_quit =ATOMIC_INIT(0); int my_fuction(void *arg){ int ret; daemonize("demo-thread"); allow_signal(SIGKILL); complete(&exit_completion); while(!signal_pending(current)){ printk("jiffies is %lu/n", jiffies); set_current_stat(TASK_INTERRUPTIBLE); schedule_timeout(10 * HZ); if(atomic_read(&kthread->terminate)) { /* we receiveda request to terminate ourself */ break; } } /* for(;;) { Ret = wait_event_interruptible(wq,condition); //可采用任何同步措施 }*/ complete_and_exit(&exit_completion,1); return0; } static int __init init(void) { thread_id = kernel_thread(my_fuction,NULL, CLONE_FS | CLONE_FILES); wait_for_completion(&exit_completion); return 0; } static void __exit finish(void) { atomic_inc(&time_to_quit); kill_proc(thread_id, SIGKILL, 1); wait_for_completion(&exit_completion); printk("Goodbye/n"); } module_init(init); module_exit(finish); MODULE_LICENSE("GPL");