操作系统4-进程,线程,进程控制——lab4内核线程管理,用户进程管理

大纲一下:最重要的还是要把知识点串起来,知道每一个后知识点概念出现的原因
进程
--------进程的概念
--------进程控制块
--------进程状态
--------三状态进程模型
--------挂起进程模型
——————————————————
线程
--------为什么引入线程
--------线程的概念
--------用户线程
--------内核线程
————————————————————
进程控制,上下文切换
进程创建fork(),进程加载exec(),进程等待与退出wait(),eixt()

一. 进程

进程是一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程
可以说,进程就是讨论程序在对数据进行处理的时候,os是如何维护这个操作过程的

1. 一个进程包含了正在运行的一个程序的所有状态信息,包括

1)程序的代码,处理的数据
2)状态寄存器(如指向下一条指令的程序计数器的值),通用寄存器(堆栈),进程占用的系统资源(打开的文件),这一部分的内容会构成之后进程控制块

2. 进程特点:

1)动态性:一个程序在执行过程中有从创建到结束的过程,即可动态地创建、结束进程
2)并发性:进程可以被独立调用并占用处理及运行
3)独立性:不同进程地工作不互相影响
4)制约性:因访问共享数据/资源或进程间同步而产生制约

  1. 进程和程序之间的联系与区别:
    1)进程是操作系统处于执行状态程序的抽象:程序=文件(静态的可执行文件),而进程=执行中的程序=程序**+ 执行状态**
    2)同一个程序的多次执行过程对应为不同进程
    3)进程执行需要资源,如内存用于保存代码和数据,CPU用于执行指令
    4)进程是程序的执行,进程有 核心态/用户态 之分
4. 进程 = 程序 + 数据 + 进程的状态信息,其中OS将进程的状态信息整合为一个进程控制块(PCB)
进程控制块:
  1. PCB是OS管理控制进程运行所用的信息集合,OS用PCB来描述进程的基本情况以及运行变化的过程,每个进程都在操作系统中有一个对应的PCB,PCB是进程存在的唯一标志:当创建一个进程的时候就会创建该进程的PCB,而当进程终止的时候就回收它的PCB,期间对进程的组织管理就是通过对PCB的组织管理来实现的

  2. 进程控制块包含三大信息:
    (1)进程标识信息:如本进程的标识,父进程标识,用户标识等
    (2)处理及状态信息保存:用户可见寄存器(用户程序可以使用的数据,地址等寄存器),控制和状态寄存器(如程序计数器和程序状态字),栈指针(过程调用/系统调用/中断处理和返回时需要用到它)
    (3)进程的控制信息:在这里插入图片描述

  3. PCB的组织方式:链表,索引表——不同状态的PCB进入不同的表

5. 进程状态
  1. 进程的生命周期管理:进程创建、进程执行、进程等待、进程抢占、进程唤醒、进程总结 /各部分详细内容都理解ok,省略冗余笔记
  2. 进程的三状态模型:进程在生命结束前处于且仅处于三种基本状态之一(运行状态,就绪状态,等待状态/阻塞状态)
  3. 进程挂起suspend:处于挂起状态的进程是映像在磁盘上的,没有占用内存空间,分为两类——阻塞挂起状态(进程在外存并等待某事件的出现),就绪挂起状态(进程在外存,但只要进入内存就可以运行)。
    (存在与挂起相关的各类状态及状态转换省略笔记
6. 状态队列

状态队列是OS维护的一组队列,用来标识系统当中所有进程的当前状态,不同的状态分别由不同的队列来表示,如就绪队列,各种类型的阻塞队列等,每个进程的PCB都根据它的状态加入到相应的队列当中在这里插入图片描述


二. 线程

为什么要引入线程?什么是线程?

  1. 一个mp3播放器的例子回答第一个问题。
  2. 线程是比进程更小的能独立运行的基本单位,线程是进程的一部分,用于描述指令流执行状态,是CPU调度的基本单位(官方回答,啥也没看出来
  3. 进程是有独立的空间,两个进程之间如果想相互访问就必须通过OS,开销比较大。而线程是进程的一部分,线程们共享进程提供的资源平台,可以直接访问进程提供的代码,数据,内存和文件等,意味着线程之间很容易实现资源共享在这里插入图片描述
  4. 优缺点:各个线程之间可以并发地执行,它们之间可以共享地址空间和文件资源;一个线程崩溃,就会导致其所属进程的所有线程崩溃。
线程的实现:用户线程,内核线程,轻量级线程
  1. 用户线程:是在用户空间实现的线程机制,不依赖于操作系统的内核,由一组用户级的线程库函数来完成线程的管理,包括线程的创建、终止、同步与调度在这里插入图片描述🔺 OS只能看到线程所属的进程,不了解用户线程的存在
    所以优点有:
    🔺每个进程有私有的线程控制块TCB列表,TCB由线程库函数维护
    🔺用户线程的切换由线程库函数实现,无需 用户态/核心态 切换,所以速度快
    🔺允许每个进程有自定义的线程调度算法
    但是缺点有:
    🔺当一个线程发起系统调用而阻塞时,整个进程会进入等待
    🔺不支持基于线程的处理机抢占,即除非当前运行线程主动放弃CPU使用权,否则它所在进程的其他线程无法抢占CPU
    🔺由于时间片是分配给进程的,所以与其他进程相比,在多线程执行时,每个线程得到的时间比较少,执行也就会比较慢

  2. 内核线程:是在操作系统的内核中实现的一种线程机制,由操作系统的内核来完成线程的创建,终止和管理在这里插入图片描述由内核来维护PCB和TCB,以达到所谓的“进程是资源分配单位,线程是处理机调度的单位”这样的严格说法
    所以内核线程的特点是:
    🔺线程执行系统调用而被阻塞不影响其他线程
    🔺线程的创建/终止/切换都是通过系统调用/内核函数在内核中实现的所以系统开销较大
    🔺时间片分配给线程,所以多线程的进程可获得更多CPU时间

  3. 轻量级进程:是内核支持的用户线程
    一个进程可以由一个或多个轻量级进程,每个轻量级进程由一个单独的内核线程来支持//略略略

  4. 用户线程和内核线程的对应关系:
    一对一:完全用内核线程来实现,对于用户态来说看到的就是内核线程,理解为一一对应的关系,(目前用的最好的
    多对一:
    多对多


三. 进程控制:进程切换,进程创建,进程加载,进程等待与退出

进程切换(上下文切换)

  1. 进程切换是暂停当前运行进程,使其从运行状态编程其他状态,并调度另一个进程让另一个进程转变为运行状态
  2. 进程切换的要求:
    1)切换前,保存进程上下文
    2)切换后,能够恢复进程上下文,进程不能显示它曾经被暂停过
    3)因为上下文切换非常频繁,所以进程切换速度要快(这个要求基本是由汇编来实现的)
  3. “保存上下文信息”是保存什么信息呢?
    ——保存整个生命周期中所维护的信息“:寄存器,CPU状态,内存地址空间
    上下文切换图示
  • 进程控制块PCB:内核的进程状态记录(就绪,等待,……)
    内核为活跃进程创建了对应的进程控制块,并将相同状态的进程的PCB放置在同一队列中(就绪队列,等待队列,僵尸队列)

进程创建 :fork

  • fork()把一个进程复制成两个进程:parent(old PID), child(new PID),会给子进程分配一个新的PID
  • exec(),加载,把一个新程序加载到内存中,重写当前进程(即当前的子进程)
    示例用fork()和exec()创建进程:
int pid == fork();//创建子进程,现在就有两个进程了
//但是父进程和子进程的返回值不同
//子进程的返回值为0,所以执行下一块
///父进程返回的是子进程的PID
if(pid==0{//子进程在这里继续
//Do anything(unmap memory,close net connections...)
exec("program",argc, argv0,argv1...);//执行,加载一个program,执行它的参数
}

fork()创建一个继承的子进程:复制父进程的所有变量和内存,所有CPU寄存器(有一个寄存器例外以便区别父子进程的ID)
父子进程的fork()返回值不一样,子进程返回0,父进程返回子进程标识符,可以使用getpid()获取子进程的PID

  • fork()执行过程对于子进程而言你,是在调用时间内对父进程地址空间的一次复制,但是要注意的是,循环中会对每一个进程进行复制,比如在一个循环三次的循环体中有一个进程的fork,那么第一次一个进程变两个进程,第二次就是4个了……

进程加载 :exec

1,允许进程“加载”一个完全不同的程序,并从main开始执行,允许加载时指定启动参数(argc,argv)
2,exec调用成功时,它是相同的进程,但是运行了不同的程序,代码段、堆栈等会完全重写
简单举例:

int pid = fork(); 
if(pid == 0)
{exec("/bin/calc");//子进程走这儿
else{
wait(pid);//父进程走这儿
}

调用fork之后,子进程会执行exec("/bin/calc")就会加载程序了:

int calc_main()
{
int q = 7;
do_init();
//……
}

3,由此可发现一个问题:fork()大部分消耗就是消耗在复制父进程的内存和CPU寄存器到子进程中,但是fork()之后就exec()的化,相当于刚刚辛辛苦苦复制的内容都会被exec调用的程序给覆盖掉即fork的内存复制并没有用,于是结合虚拟内存提出了一个轻量级的fork()叫vfork()。具体有需要再看看88

进程等待与退出:是父子进程的一种交互,来完成进程的回收

1.等待:wait()系统调用用于父进程等待子进程的结束

①子进程结束时通过exit()向父进程返回一个值
②父进程通过wait()接受并处理返回值
但是父进程先等待还是子进程先退出即①和②不一样的先后顺序会导致不一样的处理:

  1. 父进程先wait():有子进程存活时父进程就进入等待状态,等待子进程的返回结果,当某子进程调用exit()时唤醒父进程,将exit()返回值作为父进程中wait的返回值
  2. 父进程wait时已经有在等待的子进程了(叫做僵尸子进程)或者子进程已经结束了:有僵尸子进程等待时,wait()立刻返回其中一个值,无子进程时wait()立刻返回
退出/终止 exit():进程结束执行时exit(),完成进程资源回

exit()系统调用功能:
1, 调用参数返回给父进程其“结果”,父进程就可以拿到这个结果
2,将占据的各种资源进行回收:关闭所有打开的文件等占用资源,释放内存,释放大部分进程相关的内核数据结构
3,检查父进程是否还活着:
▲如果父进程还活着,那么保留结果的值直到父进程需要它,自己进入僵尸状态(zombie/defunct)
▲如果父进程已经结束,对应上面就是父进程已经wait了,那么此时父进程已经在第一步的时候就拿到这个结果了,它可以直接释放所有的数据结构和进程结果了
▲清理所有等待的僵尸进程

  • wait()和exit()相互对应彼此交互,父进程在wait时检查子进程,子进程在exit时检查父进程,最后进程终止资源回收

实验部分

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值