一、进程

  1、进程就是处于执行期的程序(目标码存放在某种存储介质上)。但进程并不仅仅局限于一段可执行程序代码,通常进程还要包含其他资源。执行线程,简称线程(thread),是在进程中活动的对象。
  2、每个线程都拥有一个独立的程序计数器、进程技和一组进程寄存器。
  3、内核调度的对象是线程,而不是进程。对Linux 而言,线程是一种特殊的进程。
  4、在现代操作系统中,进程提供两种虚拟机制:虚拟处理器和虚拟内存。
  5、程序本身并不是进程,进程是处于执行期的程序以及相关的资源的总称。
  6、Linux 系统中,这通常是调用fork()系统的结果,该系统调用通过复制一个现有进程来创建一个全新的进程。调用fork()的进程称为父进程,新产生的进程称为子进程。在该调用结束时, 在返回点这个相同位置上,父进程恢复执行,子进程开始执行。fork()系统调用从内核返回两次: 一次回到父进程,另一次回到新产生的子进程。通常,创建新的进程都是为了立即执行新的、不同的程序,而接着调用exec。这组函数就可以创建新的地址空间,并把新的程序载入其中。最终,程序通过exi的系统调用退出执行。父进程可以通过wait4()系统调用查询子进程是否终结。
 
二、进程描述符及任务结构
  1、内核把进程的列表存放在叫做任务队列(task list) 的双向循环链表中。链表中的每一项都是类型为task_struct、称为进程描述符(process descriptor)的结构,该结构定义在<linux/sched.h> 文件中。进程描述符中包含的数据能完整地描述一个正在执行的程序:它打开的文件,进程的地址空间,挂起的信号,进程的状态,还有其他更多信息。
  2、分配进程描述符
  • 每个任务的thread_info 结构在色的内核栓的尾端分配。结构中task 域中存放的是指向该任务实际task_struct 的指针。
  • 进程描述符的存放内核通过一个唯一的进程标识值(process identification value)或PID 来标识每个进程。PID 是一个数,表示为pid_t 隐含类型,实际上就是一个int类型。
  • 在内核中,访问任务通常需要获得指向其task_struct 的指针,有的硬件体系结构可以拿出一个专门寄存器来存放指向当前进程task_struct的指针,用于加快访问速度。

  3、进程状态进程描述符中的state域描述了进程的当前状态。该域的值也必为下列五种状态标志之:

  4、进程上下文当一个程序调执行了系统调用或者触发了某个异常,它就陷入了内核空间。此时,我们称内核“代表进程执行”并处于进程上下文中。

  5、进程家族树所有的进程都是PID 为1 的init 进程的后代。内核在系统启动的最后阶段启动init 进程。该进程读取系统的初始化脚本( initscript)并执行其他的相关程序,最终完成系统启动的整个过程。系统中的每个进程必有一个父进程, 相应的,每个进程也可以拥有零个或多个子进程。拥有同一个父进程的所有进程被称为兄弟。每个task_struct 都包含一个指向其父进程tast_struct、叫做parent 的指针,还包含一个称为children 的子进程链表。所以,对于当前进程, 可以通过下面的代码在得其父进程的进程描述符:structtaskstruct*my_parent = current- >parent;对于给定的进程,获取链表中的下一个进程:list_entry(task->tasks.next , struct task_ s truct, tasks)在取前一个进程的方撞与之相同:list_ entry(task->tasks. prev, s truct task_ struct, tasks)

三、进程创建Unix 

  1、采用了与众不同的实现方式,分解到两个单独的函数中去执行:fork() 和exec().首先, fork()通过拷贝当前进程创建一个子进程。子进程与父进程的区别仅仅在于PID(每个进程唯一)、PPID (父进程的进程号,子进程将其设置为被拷贝进程的PID )和某些资源和统计量(例如,挂起的信号,它没有必要被继承)。exec()函数负责读取可执行文件并将其载入地址空间开始运行。3.3.1 写时拷贝传统的fork()系统调用直接把所有的资源复制给新创建的进程。Linux 的fork()使用写时拷贝( copy-on-write)页实现。

  2、只有在需要写入的时候,数据才会被复制,从而使各个进程拥有各自的拷贝。fork()的实际开销就是复制父进程的页表以反给予进程创建唯一的进程描述符。   

  3、fork()Linux 通过clone()系统调用实现fork() 。这个调用通过一系列的参数标志来指明父、子进程需要共享的资源。fork()、vfork()和clone()库函数都根据各自需要的参数去调用clone(),然后由clone()去调用do_fork()。do_fork 完成了创建中的大部分工作,它的定义在kemeVfork.c 文件中。该函数调用copy_process()函数,然后让进程开始运行。


  4、vfork()除了不拷贝父进程的页表项外, vfork()系统调用和fork()的功能相同。子进程作为父进程的一个单独的钱程在它的地址空间里运行,父进程被阻塞,直到子进程退出或执行exec()。vfork()系统调用的实现是通过向clone()系统调用传递一个特殊标志来进行的。
  • 1)在调用copy_process()时, task_struct 的vfor_done 成员被设置为NULL 。
  • 2)在执行do_fork()时,如果给定特别标志,则vfork_done 会指向一个特定地址。
  • 3)子进程先开始执行后,父进程不是马上恢复执行,而是一直等待,直到子进程通过vfork_done 指针向它发送信号。
  • 4) 在调用mm_release()时,该函数用于进程退出内存地址空间, 并且检查vfork_done 是否为空,如果不为空,则会向父进程发送信号。
  • 5)回到do_fork(),父进程醒来并返回。
 
四、线程在Linux中的实现线程机制
  1、提供了在同一程序内共享内存地址空间运行的一组线程。这些线程还可以共享打开的文件和其他资源。
  2、创建线程线程的创建和普通进程的创建类似,只不过在调用clone()的时候需要传递一些参数标志来指明需要共享的资源
  • clone(CLONE_VMclone_CLONE_FILBSCLONE_SIGHAND )
  • 递给clone()的参数标志决定了新创建进程的行为方式和父子进程之间共享的资源种类

  3、内核线程内核经常需要在后台执行一些操作。这种任务可以通过内核线程( kernel thread)完成一独立运行在内核空间的标准进程。
  4、内核线程和普通的进程的区别在于内核线程没有独立的地址空间(实际上指向地址空间的mm 指针被设置为NULL)。它们只在内核空间运行,从来不切换到用户空间去。内核进程和普通进程一样,可以被调度,也可以被抢占。
  5、内核钱程启动后就一直运行直到调用do_exit()退出,或者内核的其他部分调用kthread_stop()退出,传递给kthread_stop()的参数kthread_create()函数返回的task_struct 结构的地址:intkthread_stop(structtask_struct *k)
  6、进程终结不管进程是怎么终结的,该任务大部分都要靠do_exit()(定义于kemel/exit.c)来完成,它要做下面这些工作:
  • 1)将tast_struct 中的标志成员设置为PF_EXITING
  • 2)调用del_timer_ sync()删除任一内核定时器。根据返回的结果,它确保没有定时器在排队,也设有定时器处理程序在运行。
  • 3)如果BSD 的进程记账功能是开启的, do_exit()调用acct_update_ integrals()来输出记账信息。
  • 4)然后调用exit_mm()函数释放进程占用的mm_struct,如果没有别的进程使用它们(也就是说,这个地址空间没有被共享),就彻底释放它们。
  • 5) 接下来调用sem_ exit()函数。如果进程排队等候IPC 信号,它则离开队列。
  • 6)调用exit_files()和exit_fs(),以分别递藏文件描述符、文件系统数据的引用计数。如果其中某个引用计数的数值降为零,那么就代表没有进程在使用相应的资源,此时可以释放。
  • 7)接着把存放在task_struct 的exit_code 成员中的任务退出代码置为由exit()提供的退出代码,或者去完成任何其他由内核机制规定的退出动作。退出代码存放在这里供父进程随时检索。
  • 8)调用exit_notify()向父进程发送信号,给子进程重新找养父,养父为钱程组中的其他钱程或者为init 进程,并把进程状态(存放在task_struct 结构的exit_state 中〉设成EXIT_ZOMBIE 。
  • 9) do_exit()调用schedule()切换到新的进程。因为处EXIT_ZOMBIE 状态的进程不会再被调度,所以这是进程所执行的最后一段代码。do_exit()永不返回。
  6、删除进程描述符进程终结时所需的清理工作和进程描述符的删除被分开执行。在父进程在得已终结的子进程的信息后,或者通知内核它并不关注那些信息后,子进程的task_struct 结构才被释放。
  7、当最终需要释放进程描述符release_task()会被调用,用以完成以下工作:
  • 1)它调用一exit_signal(),该函数调用_unhash proc(),后者又调用detach_pid()从pidhash上删除该进程,同时也要从任务列表中删除该进程。
  • 2) _exit_sal()释放目前僵死进程所使用的所有剩余资源,并进行最终统计和记录。
  • 3)如果这个进程是钱程组最后一个进程,并且领头进程已经死掉,那么release_task()就要通知僵死的领头进程的父进程.的release_task()调用put_task_ struct()辑放进程内核和read_info 结构所占的页,并释放tast_struct 所占的slab 高速缓存。
 

《Linux内核设计与实现》 第三章学习笔记的更多相关文章

  1. LINUX内核设计与实现第三周读书笔记

    LINUX内核设计与实现第三周读书笔记 第一章 LINUX内核简介 1.1 Unix的历史 1969年的夏天,贝尔实验室的程序员们在一台PDR-7型机上实现了Unix这个全新的操作系统. 1973年, ...

  2. Linux内核设计与实现 第三章

    1. 进程和线程 进程和线程是程序运行时状态,是动态变化的,进程和线程的管理操作都是由内核来实现的. Linux中的进程于Windows相比是很轻量级的,而且不严格区分进程和线程,线程不过是一种特殊的 ...

  3. 《Linux内核分析》之第三章读书笔记

    进程管理 进程是处于执行期的程序以及相关的资源的总称,也称作任务.执行线程,简称线程,是在进程中活动的对象. 可以两个或两个以上的进程执行同一个程序 也可以两个或两个以上并存的进程共享许多资源 内核调 ...

  4. 《Linux内核设计与实现》第四周读书笔记——第五章

    <Linux内核设计与实现>第四周读书笔记--第五章 20135301张忻 估算学习时间:共1.5小时 读书:1.0 代码:0 作业:0 博客:0.5 实际学习时间:共2.0小时 读书:1 ...

  5. linux及安全《Linux内核设计与实现》第一章——20135227黄晓妍

    <linux内核设计与实现>第一章 第一章Linux内核简介: 1.3操作系统和内核简介 操作系统:系统包含了操作系统和所有运行在它之上的应用程序.操作系统是指整个在系统中负责完成最基本功 ...

  6. 《Linux内核设计与实现》Chapter 3 读书笔记

    <Linux内核设计与实现>Chapter 3 读书笔记 进程管理是所有操作系统的心脏所在. 一.进程 1.进程就是处于执行期的程序以及它所包含的资源的总称. 2.线程是在进程中活动的对象 ...

  7. 《Linux内核设计与实现》Chapter 1 读书笔记

    <Linux内核设计与实现>Chapter 1 读书笔记 一.Unix的特点 Unix从Multics中产生,是一个强大.健壮和稳定的操作系统. 特点 1.很简洁 2.在Unix系统中,所 ...

  8. 《Linux内核设计与实现》Chapter 2 读书笔记

    <Linux内核设计与实现>Chapter 2 读书笔记 一.获取内核源码 1.使用Git 我们曾经在以前的学习中使用过Git方法 $ git clone git://git.kernel ...

  9. 《Linux内核设计与实现》Chapter 5 读书笔记

    <Linux内核设计与实现>Chapter 5 读书笔记 在现代操作系统中,内核提供了用户进程与内核进行交互的一组接口,这些接口的作用是: 使应用程序受限地访问硬件设备 提供创建新进程与已 ...

  10. 《Linux内核设计与实现》Chapter 18 读书笔记

    <Linux内核设计与实现>Chapter 18 读书笔记 一.准备开始 一个bug 一个藏匿bug的内核版本 知道这个bug最早出现在哪个内核版本中. 相关内核代码的知识和运气 想要成功 ...

随机推荐

  1. sed命令替换字符包含斜杠\,引号的处理方法

    在字符替换中,可能会遇见引号,“/”等的替换,这时应该注意,sed的命令原型是: sed -i  "s/oldstring/goalstring/g" file 如果一个路径是da ...

  2. 关于var与function的解析顺序问题

    先给几段代码,看看你能知道运行结果不 function example1() { var f = function() {return 1;}; return f; var f = function( ...

  3. BZOJ1024:[SCOI2009]生日快乐(DFS)

    Description windy的生日到了,为了庆祝生日,他的朋友们帮他买了一个边长分别为 X 和 Y 的矩形蛋糕. 现在包括windy,一共有 N 个人来分这块大蛋糕,要求每个人必须获得相同面积的 ...

  4. Linux下安装ElasticSearch 5 和配置外部访问

    https://www.cnblogs.com/hts-technology/p/8477291.html (一)ElasticSearch需要jdk1.8以上版本的支持,所以需要先安装jdk.lin ...

  5. 【js】 ==与===区别

    1.对于string,number等基础类型,==和===是有区别的 1)不同类型间比较,==之比较“转化成同一类型后的值”看“值”是否相等,===如果类型不同,其结果就是不等 2)同类型比较,直接进 ...

  6. Qt 编程指南 9 软件打包

    Qt 官方开发环境使用的动态链接库方式,在发布生成的exe程序时,需要复制一大堆 dll,如果自己去复制dll,很可能丢三落四,导致exe在别的电脑 里无法正常运行.因此 Qt 官方开发环境里自带了一 ...

  7. Linux运维故障排查思路

    linux系统故障 网络问题 linux系统无响应 linux系统无法启动 linux系统故障处理思路 1.重视报错信息,一般情况下此提示基本定位了问题的所在 2.查阅日志文件,系统日志和应用日志 3 ...

  8. timeout可以实现当一个命令在规定时间内不返回就强制返回的功能 + 杀毒安装ClamAV nmap 速度 比Telnet 快

    [root@xiaowei ~]# cat telnetport.sh #!/bin/bash Port=25223 timeout 2 ssh root@127.0.0.1 "telnet ...

  9. 前后端交互json字符串

    //将需要的参数转成json字符串,然后用utf-8编码 var obj = encodeURIComponent(JSON.stringify(this.categories),"utf- ...

  10. Django 学习第三式

    1.Django请求生命周期 两种情况:最终返回的是字符串 1.-> URL对应关系(匹配) -> 视图函数 -> 返回用户字符串 2.-> URL对应关系(匹配) -> ...