博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux内核学习----进程管理
阅读量:2177 次
发布时间:2019-05-01

本文共 2679 字,大约阅读时间需要 8 分钟。

进程的管理

1、进程

进程:处于执行期的程序以及相关资源的总称,(进程是正在执行的程序代码的实时结果)包含其他资源:

  • 打开的文件
  • 挂起的信号
  • 内核内部数据
  • 处理器状态
  • 一个或多个具有内存映射的内存地址空间
  • 一个或多个线程
  • 存放全局变量的数据段
    执行线程:(线程)进程中活动的对象,拥有独立的程序计数器,进程栈和一组进程寄存器,是内核调度对象,在Linux中对进程和线程不做特别区分
    操作系统中进程中的两种虚拟机制:虚拟处理器和虚拟内存
虚拟处理器:实际计算机里面可能有许多进程正在分享一个处理器,虚拟处理器会给进程一个假象,让进程认为自己有一个cpu虚拟内存:让进程在分配和管理内存时觉得自己拥有整个系统所有的内存资源线程之间可以共享虚拟内存,但是都拥有各自的虚拟处理器

2、进程描述符及任务结构

任务队列:用于内核中存放进程的列表,双向循环链表,链表中的每项类型是task_struct(进程描述符)

task_struct中包含的信息:

  • 打开的文件

  • 进程的地址空间

  • 挂起的信号

  • 进程的状态

    1、分配进程描述符

    进程描述符和内核栈

    在Linux中使用slab分配器动态生成task_struct,只需在栈底或栈顶创建一个新的结构struct thread_info,每个任务的thread_info结构在它的内核栈的尾端分配

    2、进程描述符的存放

    内核中使用进程标识值或pid来标识进程,默认pid最大值是32768(short int的最大值)为了兼容老版本

    根据硬件体系的不同对于获取task_struct指针方式不同:

  • a:使用专门的寄存器来存放执行当前进程task_struct的指针加快访问速度

  • b:在x86中由于寄存器不富余,使用在内核栈尾创建thread_info结构,通过计算间接地查找task_struct结构

    现在操作系统中可以通过修改/proc/sys/kernel/pid_max来提高上限

    3、进程的状态

    内核中使用set_task_state(task, state)将进程task设置为state状态

    进程的状态(五种),进程状态图:

    在linux的初始版本中是三种状态,运行,停止,准备-1 unrunnable, 0 runnable, >0 stopped

a、TASK_RUNNING(运行)–进程是可执行的,正在执行或在运行队列中等待,是进程在用户空间中执行的唯一可能的状态

b、TASK_INTERRUPTIBLE(可中断)–进程正在睡眠(阻塞)
c、TASK_UNINTERRUPTIBLE(不可中断)–该状态中进程对信号不做响应
d、_TASK_TRACDED—被其他进程跟踪的进程(使用ptrace对调试进程进行跟踪)
e、_TASK_STOPPED(停止)—进程停止执行,在收到SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOUT等信号时
进程状态转换
## 4、进程家族树
在Linux中进程之间是存在继承关系的,所有的进程都是pid为1的init进程的后代
init进程的启动:内核在系统启动的最后阶段启动init进程,由该进程最终完成系统启动(init进程的描述符是作为init_task静态分配)
系统中进程之间的关系:每个进程必有一个父进程,每个进程也拥有0或多个子进程,有同一个父进程的是兄弟,进程之间的关系存放在task_struct中,在task_struct中都有一个指向其父进程的指针(parent)和children的子进程链表

3、进程创建

Unix中进程创建使用fork()和exec()。

fork拷贝当前进程创建一个子进程,子进程和父进程之间的区别:pid、ppid(父进程的进程号)和特有资源和统计量
exec函数负责读取可执行文件并将其载入地址空间运行
## 1、写时拷贝
Linux的fork使用写时拷贝(copy-on-write)页实现
写时拷贝:是一种可以推迟甚至免除拷贝数据的技术,内核并不会复制整个进程地址空间,而是让父子进程共享同一个拷贝
优点:只有在需要才会数据拷贝,在不需要时是以只读的方式共享,避免拷贝大量不需要的数据
## 2、fork()
Linux通过clone()系统调用实现fork(fork,vfork,_clone是根据不同的参数调用clone),通过参数指定父子进程需要共享的资源,clone调用do_fork()
copy_process()完成的工作:
a、通过dup_task_struct()创建新进程的内核栈、thread_info结构和task_struct,这些和父进程相同
b、检查并确保新创建进程后,用户的进程数不超过资源限制
c、将子进程描述符中的值清0或设为初始值(主要是统计值)
d、通过copy_flags()以更新task_struct中的flags成员,PF_SUPERPRIV(表示是否拥有root权限)被清0,PF_FORKNOEXEC(表示进程还没调用exec)被设置
e、分配新的pid(alloc_pid)
f、根据传递给clone的参数和标志,copy_process()拷贝或共享打开的文件、文件系统信息、信号处理函数、进程地址空间和命名空间等。一般这些资源会被给定进程的所有线程共享
g、返回一个指向子进程的指针
vfork和fork之间的不同:vfork不拷贝父进程的页表

4、线程在Linux中的实现

线程机制:是现代编程技术中常用的抽象概念,提供在同一程序中共享内存地址空间运行的一组线程

Linux中从内核的角度没有线程的概念,而是将线程当作进程来处理的,每个线程都有自己的task_struct,线程是一个可以和其他线程共享资源的特殊进程

特别说明

内核线程:内核线程和普通的进程之间的区别在于内核线程没有独立的地址空间(实际指指向地址空间的mm指针被设置为NULL),只在内核空间运行
通过ps -ef查看内核线程

5、进程终结

进程需要终结并在终结时内核需要回收资源并告知父进程,进程的析构时自身引起的通过调用exit()系统调用

exit()调用do_exit()回收资源,调用release_task()释放进程描述符

特殊点:孤儿进程

孤儿进程:父进程在子进程退出之前退出
保证孤儿进程退出的机制:给子进程所在当前的进程组中找一个进程作为父亲,如果不行就使用init作为父进程
在do_exit中会调用exit_notify调用forget_original_parent执行寻找父进程的过程

转载地址:http://ucfkb.baihongyu.com/

你可能感兴趣的文章
走进JavaWeb技术世界9:Java日志系统的诞生与发展
查看>>
走进JavaWeb技术世界10:从JavaBean讲到Spring
查看>>
走进JavaWeb技术世界11:单元测试框架Junit
查看>>
走进JavaWeb技术世界12:从手动编译打包到项目构建工具Maven
查看>>
走进JavaWeb技术世界13:Hibernate入门经典与注解式开发
查看>>
走进JavaWeb技术世界14:Mybatis入门
查看>>
走进JavaWeb技术世界16:极简配置的SpringBoot
查看>>
初探Java设计模式1:创建型模式(工厂,单例等)
查看>>
初探Java设计模式2:结构型模式(代理模式,适配器模式等)
查看>>
初探Java设计模式3:行为型模式(策略,观察者等)
查看>>
初探Java设计模式4:一文带你掌握JDK中的设计模式
查看>>
初探Java设计模式5:一文了解Spring涉及到的9种设计模式
查看>>
Java集合详解1:一文读懂ArrayList,Vector与Stack使用方法和实现原理
查看>>
Java集合详解2:一文读懂Queue和LinkedList
查看>>
Java集合详解3:一文读懂Iterator,fail-fast机制与比较器
查看>>
Java集合详解4:一文读懂HashMap和HashTable的区别以及常见面试题
查看>>
Java集合详解5:深入理解LinkedHashMap和LRU缓存
查看>>
Java集合详解6:这次,从头到尾带你解读Java中的红黑树
查看>>
Java集合详解7:一文搞清楚HashSet,TreeSet与LinkedHashSet的异同
查看>>
Java集合详解8:Java集合类细节精讲,细节决定成败
查看>>