进程管理

进程

进程

  1. 什么是进程

处于执行期间的程序

  1. 进程资源

通常包括的资源:打开的文件,挂起的信号,内核内部数据,处理器状态,一个或多个具有
内存映射的内存地址空间及一个或多个执行线程。存放全局变了的数据段等。

进程创建

  1. 调用fork,在该调用结束时,在返回点相同位置,父进程恢复执行,子进程开始执行。
    fork调用一次,从内核返回两次。

  2. fork实际由clone()系统调用实现

  3. 程序通过调用exit()系统调用退出,这个函数会终结进程并将其占有的资源释放

进程描述符及任务结构

进程在内核进程也叫task

内核把进程的列表存放到叫做任务队列task list的双向循环链表中。链表的每一项
都是task_struct,成为进程描述符的结构。
进程描述符中包含的数据可以完整的描述一个正在执行的进程:他打开的文件,进程地址空间
,挂起的信号,进程的状态还有其他信息

进程队列

进程描述符和内核栈

在这里插入图片描述
每个thread_info结构在他的内核栈尾端分配,结构中的task域中存放当前任务实际的task_struct指针

进程状态

进程描述符中的state描述进程的当前状态,每个进程的必然处于五种状态之一

task_running
task_interruptible
task_uninterruptible
__task_traced
__task_stopped

设置某个进程的状态。set_task_state(task,state);

进程上下文

程序在用户空间执行,当执行系统调用或触发一次,就陷入内核,我们称为内核代表
进程执行并处于进程上下文中。

进程家族树

task_struct 中包含父进程指针parent和指向子进程链表的children

创建过程

fork()和exec()函数,首先fork通过拷贝当前进程创建一个子进程。子进程与父进程的区别
仅仅在于pid,ppid和某些资源和统计量(挂起的信号)

linux通过clone系统调用实现fork(),这个调用通过一系列的参数标志来指明父子进程
需要共享的资源

do_fork完成了创建中的大部分工作,该函数调用copy_process函数,让程序开始运行
copy_process函数流程

  1. dup_task_struct 创建一个内核栈,thread_info结构和task_struct,这些值与当前进程
    完全相同。

linux通过clone系统调用实现fork(),这个调用通过一系列的参数标志来指明父子进程
需要共享的资源

do_fork完成了创建中的大部分工作,该函数调用copy_process函数,让程序开始运行
copy_process函数流程
dup_task_struct 创建一个内核栈,thread_info结构和task_struct,这些值与当前进程
完全相同。

linux通过clone系统调用实现fork(),这个调用通过一系列的参数标志来指明父子进程
需要共享的资源

do_fork完成了创建中的大部分工作,该函数调用copy_process函数,让程序开始运行
copy_process函数流程

  1. dup_task_struct 创建一个内核栈,thread_info结构和task_struct,这些值与当前进程
    完全相同。
  2. 检查并确保当前用户所有的进程数没有超出限制
  3. 子进程使自己与父进程区别开,进程描述符中的许多成员要被清0或初始值
  4. 子进程状态被设置为task_uninterruptible,保证不会被投入运行
  5. 调用copy_flags以更新task_struct的flags成员。表明用户是否拥有超级权限的
    PF_SUPERPRIV标志被清0,表明进程还没有调用exec函数的PF_FORKNOEXEC标志被设置
  6. 调用alloc_pid 为信进程分配一个有效pid
  7. 根据clone参数标志,拷贝或共享打开的文件,文件系统信息,信号处理函数,进程地址空间和命名空间等
  8. 最后做扫尾工作并返回一个指向子进程的指针
  9. 返回到do_fork,如果copy_process 返回成功,新创建的子进程被唤醒并让其投入运行

线程

  1. 什么是线程

是在进程中的活动的对象

  1. 线程资源

拥有独立的程序计数器,进程栈和一组寄存器。内核调度的基本单位。

线程在linux 中的实现

从内核角度来说没有线程概念,linux把线程当作进程来实现,线程仅仅被视为一个与其他进程共享某些资源的进程
每个线程拥有自己的task_struct。

创建线程

线程创建和普通进程创建类似,只不过是调用clone()的时候传递一些参数标志来指明需要共享的资源
clone(clone_vm | clone_fs | clone_files | clone_sighand,0)

内核线程和普通进程间的区别在于内核线程没有独立的地址空间,只在内核空间运行,从来不切换到用户空间.

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

调用ktread_run运行

进程终结

调用exit()

将task_struct 中的标志设置为PF_EXITING
调用del_timer_sync删除任一内核定时器
调用exit_mm()释放进程占有的mm_struct
调用sem__exit(),如果进程等候IPC信号,他则离开队列
调用exit_files 和exit_fs(),递减文件描述符,文件系统数据的引用计数,如果某个
引用计数为0,就代表没有进程使用,此时可以释放。
把task_struct的exit_code设置为exit()函数提供的值
调用exit_notify()向父进程发送信号,给子进程重新找养父。
do_exit()调用chedule()切换到新的进程。do_exit()永不返回。
进程相关联的资源全部释放,进程不可运行并处于exit_zombie退出状态。thread_info和task_struct结构唯一母的是向父进程提供信息。父进程检索信息后,通知内核是无用信息,由进程所持有的剩余资源被释放。

孤儿进程

父进程在子进程之前退出,必须有机制来保证子进程找到一个新的父亲。否则这些成为孤儿的进程就会永远处于僵死状态。
do_exit调用exit_notify()
调用forget_original_parent()
调用find_new_reaper来寻父进程(进程组内的其他进程,如果找不到就找init进程)
调用ptrace_exit_finsish(),进行寻父过程,不过这次是给ptrace的子进程寻找父亲
init进程会例行调用wait()来检查其子进程,清除所有与其相关的僵尸进程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值