找回密码
 注册
关于网站域名变更的通知
查看: 356|回复: 1
打印 上一主题 下一主题

Linux内核设计与实现之Linux的进程

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-10-10 13:53 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
进程是所有操作系统的核心概念,同样在linux上也不例外。
主要内容:
  • 进程和线程
  • 进程的生命周期
  • 进程的创建
  • 进程的终止! v$ {$ w) [6 P+ |# p7 m: B
1. 进程和线程
进程和线程是程序运行时状态,是动态变化的,进程和线程的管理操作(比如,创建,销毁等)都是有内核来实现的。
Linux中的进程于Windows相比是很轻量级的,而且不严格区分进程和线程,线程不过是一种特殊的进程。
所以下面只讨论进程,只有当线程与进程存在不一样的地方时才提一下线程。
3 F% H! `7 y) S9 W
进程提供2种虚拟机制:虚拟处理器和虚拟内存
每个进程有独立的虚拟处理器和虚拟内存,
每个线程有独立的虚拟处理器,同一个进程内的线程有可能会共享虚拟内存。
% J) n* e+ P' w' |
内核中进程的信息主要保存在task_struct中(include/linux/sched.h)
进程标识PID和线程标识TID对于同一个进程或线程来说都是相等的。
Linux中可以用ps命令查看所有进程的信息:
ps -eo pid,tid,ppid,comm7 d2 j& U( k4 {) \

$ s: o- ~! N3 n2 b6 ^4 d# F7 z2. 进程的生命周期
进程的各个状态之间的转化构成了进程的整个生命周期。

" \+ s! T' ^2 U2 H3 z$ O0 ^3. 进程的创建
Linux中创建进程与其他系统有个主要区别,Linux中创建进程分2步:fork()和exec()。
fork: 通过拷贝当前进程创建一个子进程
exec: 读取可执行文件,将其载入到内存中运行
创建的流程:
  • 调用dup_task_struct()为新进程分配内核栈,task_struct等,其中的内容与父进程相同。
  • check新进程(进程数目是否超出上限等)
  • 清理新进程的信息(比如PID置0等),使之与父进程区别开。
  • 新进程状态置为 TASK_UNINTERRUPTIBLE
  • 更新task_struct的flags成员。
  • 调用alloc_pid()为新进程分配一个有效的PID
  • 根据clone()的参数标志,拷贝或共享相应的信息
  • 做一些扫尾工作并返回新进程指针
    . w# a9 ~' t: q$ ?) Y+ }
创建进程的fork()函数实际上最终是调用clone()函数。
创建线程和进程的步骤一样,只是最终传给clone()函数的参数不同。
比如,通过一个普通的fork来创建进程,相当于:clone(SIGCHLD, 0)
创建一个和父进程共享地址空间,文件系统资源,文件描述符和信号处理程序的进程,即一个线程:clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0)
在内核中创建的内核线程与普通的进程之间还有个主要区别在于:内核线程没有独立的地址空间,它们只能在内核空间运行。
这与之前提到的Linux内核是个单内核有关。
9 `( Z/ i9 T, v+ p0 D5 _
4. 进程的终止
和创建进程一样,终结一个进程同样有很多步骤:

) N  `+ v# {% S! U7 z
子进程上的操作(do_exit)
  • 设置task_struct中的标识成员设置为PF_EXITING
  • 调用del_timer_sync()删除内核定时器, 确保没有定时器在排队和运行
  • 调用exit_mm()释放进程占用的mm_struct
  • 调用sem__exit(),使进程离开等待IPC信号的队列
  • 调用exit_files()和exit_fs(),释放进程占用的文件描述符和文件系统资源
  • 把task_struct的exit_code设置为进程的返回值
  • 调用exit_notify()向父进程发送信号,并把自己的状态设为EXIT_ZOMBIE
  • 切换到新进程继续执行
    0 }1 C+ C2 O8 {/ J8 f# b
子进程进入EXIT_ZOMBIE之后,虽然永远不会被调度,关联的资源也释放掉了,但是它本身占用的内存还没有释放,5 l" [5 s" {, O/ [' e
比如创建时分配的内核栈,task_struct结构等。这些由父进程来释放。
父进程上的操作(release_task)
父进程受到子进程发送的exit_notify()信号后,将该子进程的进程描述符和所有进程独享的资源全部删除。
从上面的步骤可以看出,必须要确保每个子进程都有父进程,如果父进程在子进程结束之前就已经结束了会怎么样呢?
子进程在调用exit_notify()时已经考虑到了这点。
如果子进程的父进程已经退出了,那么子进程在退出时,exit_notify()函数会先调用forget_original_parent(),然后再调用find_new_reaper()来寻找新的父进程。
find_new_reaper()函数先在当前线程组中找一个线程作为父亲,如果找不到,就让init做父进程。(init进程是在linux启动时就一直存在的)
- {! r, ?  ]5 e1 d4 {

该用户从未签到

2#
发表于 2020-10-10 16:19 | 只看该作者
Linux内核设计与实现之Linux的进程
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-6-30 05:00 , Processed in 0.078125 second(s), 26 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表