20135302魏静静——课本第3章学习笔记

第三章   进程管理

本章主要内容:

  • 进程和线程
  • 进程的任务结构
  • 进程和线程的创建
  • 进程的终止

1. 进程和线程

  • 进程:进程就是处于执行期的程序,实际上,进程就是正在执行的程序代码的实时结果;
  • 线程:执行线程,简称线程,是进程中活动的对象(每个线程拥有独立的程序计数器、进程栈、和一组进程寄存器),内核调度的对象是线程,不是进程
进程提供2种虚拟机制:虚拟处理器和虚拟内存
每个进程有独立的虚拟处理器和虚拟内存,
每个线程有独立的虚拟处理器,同一个进程内的线程有可能会共享虚拟内存。
内核中进程的信息主要保存在task_struct中(include/linux/sched.h)
进程标识PID和线程标识TID对于同一个进程或线程来说都是相等的。

fork()系统调用:

通过复制一个现有进程来创建一个全新的进程;接这调用exce()函数,可以创建新的地址空间,并把程序载入其中;最后,程序通过exit()系统调用退出调用。这个函数会终结进程并将其占用的资源释放掉。

*fork()实际上是由clone()系统调用实现的

Linux中可以用ps命令查看所有进程的信息:

ps -eo pid,tid,ppid,comm

2. 进程的任务结构

下图为进程的数据结构简化图:
  • 双向循环链表中,每一项都是类型为task_struct,称为进程描述符的结构;该结构定义在<sched.h>文件中
  • 进程描述符中包含的数据能完整地描述一个正在执行的程序
  • 每个任务的thread_info结构在它的内核栈的尾端分配。结构中task域中存放的是指向该任务实际的task_struct的指针
  • 进程描述符的PID的最大值实际就是系统中允许同时存在的进程的最大数目;
  • 进程描述符中的state域描述了进程的当前状态;进程的各个状态之间的转化构成了进程的整个生命周期,进程必然处于五个状态的一种:
    • task_running
    • task_interruprtion
    • task_uninterruption
    • task_traced
    • task_stopped

*调整某个进程的状态,这时使用set_task_state函数
  • 进程只有通过这些接口才能陷入内核执行——对内核的所有访问都必须通过这些接口
     系统中的每个进程必有一个父进程,相应的,每个进程也可以拥有零个或者多个子进程;拥有同一个父进程的所有进程被称为兄弟;进程间的关系存放在进程描述符中

3. 进程和线程的创建

  • Linux中创建进程分2步:
fork: 通过拷贝当前进程创建一个子进程
exec: 读取可执行文件,将其载入到内存中运行
  • 创建的流程:
  1. 调用dup_task_struct()为新进程分配内核栈,task_struct等,其中的内容与父进程相同。
  2. check新进程(进程数目是否超出上限等)
  3. 清理新进程的信息(比如PID置0等),使之与父进程区别开。
  4. 新进程状态置为 TASK_UNINTERRUPTIBLE
  5. 更新task_struct的flags成员。
  6. 调用alloc_pid()为新进程分配一个有效的PID
  7. 根据clone()的参数标志,拷贝或共享相应的信息
  8. 做一些扫尾工作并返回新进程指针
  • 创建进程的fork()函数实际上最终是调用clone()函数。
  • 创建线程和进程的步骤一样,只是最终传给clone()函数的参数不同。
  • linux通过clone()系统调用实现fork();do_fork完成创建中的大部分工作,定义在kernel/fork.c文件中
  • 除了不拷贝父进程的页表项外,vfork()系统调用和fork功能相同;vfork()系统调用的实现是通过向clone()系统调用传递一个特殊标志来进行的
比如,通过一个普通的fork来创建进程,相当于:clone(SIGCHLD, 0)
创建一个和父进程共享地址空间,文件系统资源,文件描述符和信号处理程序的进程,即一个线程:clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0)
  • 创建线程:与普通进程的创建类似,只不过调用clone()时候需要传递一些参数标志来指明需要共享的资源,参数标志决定了新创建进程的行为方式和父子进程之间共享的资源种类
  • 内核线程和普通的进程间的区别在于内核线程没有独立的地址空间,它们只在内核空间进行,从来不切换到用户空间。内核进程和普通进程一样,可以被调度,也可以被抢占
  • kthread内核进程通过clone()系统调用而创建。新的进程将运行threadfn函数,传递的参数为data
在内核中创建的内核线程与普通的进程之间还有个主要区别在于:内核线程没有独立的地址空间,它们只能在内核空间运行。

4. 进程的终止

和创建进程一样,终结一个进程同样有很多步骤:

  • 子进程上的操作(do_exit)
  1. 设置task_struct中的标识成员设置为PF_EXITING
  2. 调用del_timer_sync()删除内核定时器, 确保没有定时器在排队和运行
  3. 调用exit_mm()释放进程占用的mm_struct
  4. 调用sem__exit(),使进程离开等待IPC信号的队列
  5. 调用exit_files()和exit_fs(),释放进程占用的文件描述符和文件系统资源
  6. 把task_struct的exit_code设置为进程的返回值
  7. 调用exit_notify()向父进程发送信号,并把自己的状态设为EXIT_ZOMBIE
  8. 切换到新进程继续执行
子进程进入EXIT_ZOMBIE之后,虽然永远不会被调度,关联的资源也释放掉了,但是它本身占用的内存还没有释放,比如创建时分配的内核栈,task_struct结构等。这些由父进程来释放。
  • 父进程上的操作(release_task)
父进程受到子进程发送的exit_notify()信号后,将该子进程的进程描述符和所有进程独享的资源全部删除。
  • 除此之外的注意事项:
在调用do_exit()之后,尽管线程已经僵死不能再运行,但是系统还是保留了它的进程描述符。

wait()这一组函数通过唯一的一个系统调用wait4()来实现linux如何存放(task_struct)和表示进程(thread_info);创建(fork()),实际上最终clone()
如果子进程的父进程已经退出了,那么子进程在退出时,exit_notify()函数会先调用forget_original_parent(),然后再调用find_new_reaper()来寻找新的父进程。
find_new_reaper()函数先在当前线程组中找一个线程作为父亲,如果找不到,就让init做父进程
时间: 2024-10-09 09:14:44

20135302魏静静——课本第3章学习笔记的相关文章

20135302魏静静——课本第4章学习笔记

第4章   进程调度 调度:调度是一个平衡的过程.一方面,它要保证各个运行的进程能够最大限度的使用CP:另一方面,保证各个进程能公平的使用CPU. 调度功能:决定哪个进程运行以及进程运行多长时间. 调度实现原理:与进程的优先级有关 Linux上调度实现的方法:O(1)的调度算法 调度相关的系统调用 4.1多任务   多任务系统可以划分为两类:非抢占式多任务( cooperative multitasking )和抢占式多任务(preemptive multitasking).像所 有Unix 的

20135302魏静静——课本第17章学习笔记

第17章   模块与设备 设备类型:在所有 Unix 系统中为了统一普通设备的操作所采用的分类. 模块: Linux 内核中用于按需加载和卸载目标码的机制. 内核对象:内核数据结构中支持面向对象的简单操作,还支持维护对象之间的父子关系. sysfs :表示系统中设备树的一个文件系统. 1. 设备类型 三种类型 块设备 字符设备 网络设备 2. 模块 1. Hello,World 模块的所有初始化函数必须符合形式:int my _ init (void); 退出函数必须符合形式:void my_e

20135302魏静静——课本1-2章学习笔记

第一章 Linux内核简介 一.Unix Unix是一个强大.健壮和稳定的操作系统. Unix——支持抢占式多任务.多线程.虚拟内存.换页.动态链接和TCP/IP网络. 二.操作系统和内核简介 操作系统是指在整个系统中负责完成最基本功能和系统管理的那些部分. 内核独立于普通应用程序,一般处于系统态,拥有受保护的内存空间和访问硬件设备的所有权限.这种系统态和被保护起来的内存空间,统称为内核空间.在系统中运行的应用程序通过系统调用来与内核通信. 应用程序完成其工作的基本行为方式是: 应用程序通过系统

20135302魏静静——课本5章学习笔记

第五章 系统调用 5.1 与内核通信 中间层 作用三个:1.为用户空间提供一种硬件的抽象接口:2.保证系统稳定和安全:3.除异常和陷入,是内核唯一的合法入口. 5.2 API.POSIX和C库 API定义了应用程序使用的编程接口(可实现系统调用). API.POSIX.C库与系统调用之间关系. 5.3 系统调用——syscall 5.3.1 系统调用号 当用户空间的进程执行一个系统调用,就用系统调用号指明到底执行哪个系统调用. sys_ni_syscall():错误号,负责“填补空缺”,返回-E

20135302魏静静——课本18章学习笔记

第十八章 调试 一.内核中的bug 内核bug的原因可能有: - 错误代码 - 同步时发生的错误,例如共享变量锁定不当 - 错误的管理硬件 - …… 内核bug发作的症状可能有: - 降低所有程序的运行性能 - 毁坏数据 - 使得系统处于死锁状态 - …… 内核开发比起用户开发要多考虑一些独特的问题,比如: - 定时限制 - 竞争条件 - …… 原因是允许多个线程在内核中同时运行. 二.通过打印来调试 1. 健壮性 弹性极佳的函数:任何时候.任何地方都能调用它 可以在中断上下文和进程上下文中被调

20135302魏静静——Linux课程期中总结

Linux期中总结 Linux课程第一周实验及总结:[http://www.cnblogs.com/20135302wei/p/5218607.html] 冯诺依曼体系结构的核心思想是存储程序计算机.在计算机中有两种指令,一是用户指令,一是系统调用. 当用户使用计算机时,计算机根据其汇编的指令一步步运行,当使用系统调用完后,再返回用户模式,保证系统的稳定. 程序中执行call的堆栈变化 汇编基础 通用寄存器 16位  32位 AX    eax 累加器BX    ebx 基址寄存器CX    e

【tapestry3笔记】--tapestry 初探,《 tapestry in action 》第一章学习笔记

由于要维护一个项目,要用到tapestry3这个老框架,虽然这个框架很老,但是在我看来ta的思想还是很先进的---面向组件编程. 由于网上资料少的可怜,辛苦找了很久终于找到一本名为<tapestry in action>的工具书,以下学习笔记均以此书为参考. 正文---tapestry初探 tapestry in action 第一章学习笔记 tapestry是一款以组件为核心的开发框架,组件就向一个黑盒子,我们无需关系组件是如何实现的,只需合理使用即可.这有点像jquery的插件,我们无需关

《Linux内核设计与实现》第一、二章学习笔记

<Linux内核设计与实现>第一.二章学习笔记 姓名:王玮怡  学号:20135116 第一章 Linux内核简介 一.关于Unix ——一个支持抢占式多任务.多线程.虚拟内存.换页.动态链接和TCP/IP网络的现代化操作系统 1.主要发展过程   1969年,贝尔实验室的程序员们设计了一个文件系统原型,最终发展演化成了Unix 1971年,Unix被移植到PDP-11型机中 1973年,整个Unix系统使用C语言进行重写,为后来Unix系统的广泛移植铺平了道路 Unix第六版(V6)被贝尔实

安卓权威编程指南 - 第五章学习笔记(两个Activity)

学习安卓编程权威指南第五章的时候自己写了个简单的Demo来加深理解两个Activity互相传递数据的问题,然后将自己的学习笔记贴上来,如有错误还请指正. IntentActivityDemo学习笔记 题目:ActivityA登录界面(用户名.密码.登陆按钮),ActivityB(Edit,返回按键:SubmitButton).A界面输入用户名和密码传到B中,B验证用户输入的用户名和密码,如果错误就返回A,并用Toast 显示用户名和密码错误:如果正确,就在第二个 activity中显示一个Edi