计算机系统课程 笔记总结 CSAPP第八章 异常控制流(8.2-8.4)

目录

8.2 进程

8.2.5 上下文切换

8.3 系统调用错误处理

8.4 进程控制

8.4.1 获取进程ID

8.4.2 创建和终止进程

8.4.3 回收子进程

8.4.4 让程序休眠

8.4.5 加载并运行程序


8.2 进程

进程

  • 定义: 一个执行中程序的实例
    • 计算机科学最深刻的概念之一
    • 不同于“程序”或“处理器”
  • 进程提供给应用程序两个关键抽象
    • 逻辑控制流 (Logical control flow)
      • 每个程序似乎独占地使用CPU
      • 通过OS内核的上下文切换机制提供
    • 私有地址空间 (Private address space)
      • 每个程序似乎独占地使用内存系统
      • OS内核的虚拟内存机制提供
  • 并发进程的控制流物理上是不相交的
  • 然而,我们可以认为并发进程是并行运行的

8.2.5 上下文切换

  • 进程由常驻内存的操作系统代码块(称为内核)管理
    • 内核不是一个单独的进程,而是作为现有进程的一部分运行
  • 控制流通过上下文切换从一个进程传递到另一个进程

8.3 系统调用错误处理


8.4 进程控制

8.4.1 获取进程ID

获取进程ID

  • pid_t getpid(void)
    • 返回当前进程的PID
  • pid_t getppid(void)
    • 返回父进程的PID

8.4.2 创建和终止进程

从程序员的角度,我们可以认为进程总是处于下面三种状态之一

  • 运行Running        
    • 进程要么在CPU上执行,要么等待被执行最终会被操作系统内核调度
  • 停止/暂停/挂起/Stopped/Paused/Hanged
    • 进程的执行被挂起且不会被调度直到收到新的信号
  • 终止Terminated
    • 进程永远地停止了,但仍占资源

 

 

  • 终止进程
    • 进程会因为三种原因终止:
      • 收到一个信号,该信号的默认行为是终止进程
      • 从主程序返回
      • 调用exit函数
        • void exit(int status)
          • 以status退出状态来终止进程
          • 常规的:正常返回状态为0,错误为非零
          • 另一种设置退出状态的方法是从主程序中返回一个整数值
        • exit 函数不返回到下一行
  • 创建进程
    • 父进程通过调用fork函数创建一个新的运行的子进程
    • int fork(void)
      • 子进程返回0,父进程返回子进程的PID
      • 新创建的子进程几乎但不完全与父进程相同:
        • 子进程得到与父进程虚拟地址空间相同的(但是独立的)一份副本(代码、数据段、堆、共享库以及用户栈)
        • 子进程获得与父进程任何打开文件描述符相同的副本
        • 子进程有不同于父进程的PID
    • fork函数:被调用一次,却返回两次
      • 返回到父进程为子进程地址(不为0
      • 返回到子进程为0

8.4.3 回收子进程

  • 想法-为什么回收?--与fork创建相反!
    • 当进程终止时,它仍然消耗系统资源
    • 称为 “僵尸zombie”进程
    • 占用内存资源、打开的IO资源等
  • 回收 (Reaping)
    • 父进程执行回收( using wait or waitpid )
    • 父进程收到子进程的退出状态
    • 内核删掉僵死子进程、从系统中删除掉它的所有痕迹
  • 父进程不回收子进程的后果:
    • 如果父进程没有回收它的僵死子进程就终止了,内核安排 init-养父进程去回收它们
      • init进程PID为1,系统启动时创建,不会终止,是所有进程的祖先
    • 长时间运行的进程应当主动回收它们的僵死子进程
      • e.g., shells and servers
  • 父进程通过wait/waitpid函数回收子进程
    • wait(&status)同waitpid(-1,&status,0)
  • int wait(int *child_status)
    • 挂起当前进程的执行直到它的一个子进程终止/停止
    • 返回已终止/停止子进程(可能很多-是个集合)的 pid
    • 等价于waitpid(-1&status0
  • pid_t waitpid(pid_t pid,int &statusp,int options)
    • pid>0 等待集合就是一个单独的子进程,进程ID=pid
    • pid=-1 等待集合是由父进程所有的子进程组成
    • pid=-n  等待集合是由进程组pid所有的子进程组成
    • Options:0 等待子进程终止

8.4.4 让程序休眠

  • unsigned int sleep(unsinged int secs)
    • 时间到则返回0
    • 若被信号中断,则会返回剩余要休眠的时间
  • unsigned int alarm(unsinged int secs)
    • 报警
  • int pause()
    • 当前进程休眠,直到收到一个信号
  • 休眠不能回收进程

8.4.5 加载并运行程序

  • int execve(char *filename, char *argv[], char *envp[])
  • 在当前进程中载入并运行程序:  loader加载器函数
    • filename:可执行文件
      • 目标文件或脚本(用#!指明解释器,如 #!/bin/bash)
    • argv:参数列表,惯例:argv[0]==filename
    • envp:环境变量列表
      • "name=value" strings (e.g., USER=droh)
      • getenv, setenv, unsetenv, printenv
  • Loader删除子进程现有的虚拟内存段,创建一组新的段(栈与堆初始化为0),并将虚拟地址空间中的页映射到可执行文件的页大小的片chunk,新的代码与数据段被初始化为可执行文件的内容,然后跳到_start………… 除了一些头部信息实际没读文件,直到缺页中断
  • 覆盖当前进程的代码、数据、栈
    • 保留:有相同的PID,继承已打开的文件描述符和信号上下文
  • Called once and never returns(调用一次并从不返回)
    • …除非有错误,例如:指定的文件不存在
发布了36 篇原创文章 · 获赞 11 · 访问量 3501

猜你喜欢

转载自blog.csdn.net/gzn00417/article/details/104236937