20201302姬正坤第六周学习笔记
Linux第三章学习笔记——Unix/Linux进程管理
一、多任务处理
多任务处理指的时同时进行几项独立活动的能力。多任务处理是通过在不同任务之间多路复用CPU执行时间来实现的。
如果切换速度够快,就会给人一种通知执行所有任务的错觉。这种逻辑并行性称为“并发”
上下文切换:
- 将当前寄存器保存到调用切换任务的堆栈中,并将堆栈指针保存到proc.ksp中
- 系统对进程进行调度,将活动就绪队列中的第一进程运行
- 恢复目前运行进程上下文
二、进程的概念
在操作系统中,任务也成为进程。进程是对映像的执行。
操作系统内核将一系列执行视为使用系统资源的单一实体。
系统资源包括内存空间、I/O设备以及最重要的CPU时间。PROC结构体包含了某个进程的所有信息。
P1进程
- 除P0之外所有进程的祖先
- 所有孤儿进程的父进程
- 处理所有僵尸进程
僵尸进程
一个子进程在其父进程还没有调用wait()或waitpid()的情况下退出。这个子进程就是僵尸进程。任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个子进程在结束时都要经过的阶段。
孤儿进程
父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。P1进程会wait()该进程结束,收集必要信息。
进程终止
正常终止
- 进程调用exit(value),发出_exit(value)系统调用来执行在操作系统内核中的kexit(value)
异常终止
- 进程因某个信号而异常终止
在这两种情况下,当进程终止时,最终都会在操作系统内核中调用 kexit()
三、Unix/Linux中的进程
守护进程
P1运行时,将执行映像更改为init程序,P1通常被称为init进程,P1的大部分子进程都是用来提供系统服务的,称为守护进程
进程的产生
- 内核启动代码强制创建P0进程,设置优先级为最低
- P0进程初始化系统,并挂载根文件系统
- 创建子进程P1,将进程切换到P1
- P1创建守护进程
- 系统启动完毕
进程执行模式切换
- 中断:外部设备发送给cpu信号,请求服务
- 陷阱:程序运行出现错误
- 系统调用:执行内核函数
四、I/O重定向
文件流和文件描述符
用于终端I/O的文件流:stdin(标准输入)、stdout(标准输出)、stderr(标准错误)
- 标准输入:
FILE *stdin -----------> FILE structure ;fd = 0
- 标准输出:
FILE *stdout -----------> FILE structure;fd = 1
- 标准错误:
FILE *stderr -----------> FILE structure;fd = 2
五、管道
管道是用于进程交换数据的单向进程件通信通道。管道有一个读取端和一个写入端。
管道操作的系统模型
- 演示管道操作
点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int pd[2],n,i;
char line[256];
int main()
{
pipe(pd);
printf("pd=[%d, %d]\n",pd[0], pd[1]);
if(fork()){
printf("parent %d close pd[0]\n",getpid());
close(pd[0]);
while(i++ < 10){
printf("parent %d writes to pipe\n",getpid());
n = write(pd[1], "I AM YOUR PAPA", 16);
printf("parent %d wrote %d bytes to pipe\n",getpid(), n);
}
printf("parent %d exit\n", getpid());
}
else{
printf("child %d close pd[1]\n", getpid());
close(pd[1]);
while(1){
printf("child %d reading from pipe\n",getpid());
if ((n = read(pd[0], line, 128))){
line[n]=0;
printf("child read %d bytes from pipe: %s\n", n, line);
}
else
exit(0);
}
}
}