从零开始学习Linux(5)----进程

目录

1.冯诺依曼体系结构

2.操作系统

3.进程

1.基本概念

2.描述进程-PCB

3.系统调用查看pid

4.系统调用创建进程-fork初识

4.进程状态

1.阻塞:

2.挂起:

3.Z-僵尸进程

僵尸进程危害:

4.孤儿进程

5.进程优先级

Linux内核进程调度队列

活动队列

过期队列

active指针和expired指针


1.冯诺依曼体系结构

独立:

        CPU:运算器和控制器

        输入设备:话筒,摄像头,键盘,鼠标,磁盘,网卡等。

        输出设备:声卡,显卡,网卡,磁盘,显示器,打印机等。

        存储器指的是内存---掉电易失

        设备是总线连接的----主板

        设备中数据的流动,本质是设备之间会进行数据的来回拷贝,拷贝的整体速度,是决定计算机效率的重要指标。

        距离CPU距离越近的存储单元,效率越高,造价高,单体容量越小。

        距离CPU越远的存储单元,效率越低,造价便宜,单体容量大。

        内存看做一个非常大的缓存介于设备和CPU之间,计算机的效率最重就变成了内存效率为主。引入内存把效率问题转化为了软件问题。

场景1:程序在运行的时候,必须把程序先加载到内存,在数据层面,CPU只和内存打交道,外设只和内存打交道。

2.操作系统

        任何计算机系统都包含一个基本的程序集合,称为操作系统(os),第一个被加载的软件是操作系统,操作系统是一个进行软硬件资源管理的软件。操作系统包括:

        1.内核(进程管理,内存管理,文件管理,驱动管理)

        2.其他程序(函数库,shell程序等)

设计操作系统的目的:

        1.与硬件交互,管理所有的软硬件资源

        2.为用户程序提供一个良好的执行环境

计算机管理硬件:

        1.描述起来,结构体

        2.组织起来,高效的数据结构

系统调用:操作系统对外表现一个整体,暴露自己的部分接口,这个接口就叫做系统调用。

库函数:对部分系统调用进行适度封装,形成了库。

3.进程

事实:

  1. 我们可以同时启动多个程序----我们一定要将多个.exe加载到内存。
  2. 操作系统要管理多个加载到内存的程序。
  3. 操作系统通过先描述再组织管理加载到内存的程序。

1.基本概念

        课本概念:程序的一个执行实例,正在执行的程序等。

        内核观点:担当分配系统资源(CPU时间,内存)的实体。

2.描述进程-PCB

        进程信息放在一个叫做进程控制块的数据结构中,为进程属性的集合。

        Linux下的PCB是:task struct

        进程=内核数据结构+可执行程序

        组织:所有运行在系统里的进程都以task_struct链表的形式存在内核里

所有对进程的控制和操作,都只和进程的PCB有关,和进程的可执行程序没有关系。

task_struct中的内容:

  • 标示符: 描述本进程的唯一标示符,用来区别其他进程。
  • 状态: 任务状态,退出代码,退出信号等。
  • 优先级: 相对于其他进程的优先级。
  • 程序计数器: 程序中即将被执行的下一条指令的地址。
  • 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
  • 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
  • I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
  • 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
  • 其他信息

创建一个这样的程序,即可查看到该进程

3.系统调用查看pid

         进程id(PID)
        父进程id(PPID)

4.系统调用创建进程-fork初识

        fork之后,代码共享,fork之后形成分支,一个为原进程(父进程),一个为它的子进程,父子进程代码共享,数据各自开辟空间,私有一份(写时拷贝),fork有两个返回值,如果成功将子进程的pid返回给父进程,将0返回给子进程。一般而言,我们想让父子做不同的事情。

        子进程被创建,是以父进程为模板的。一个进程崩溃了,不会影响其他进程,进程之间是具有独立性的,互相不能影响。可以用同一个变量名,表示不同的内存

4.进程状态

        进程排队一定是在等待某种资源,进程不是一直在运行的,可能在等待某种软硬件资源,进程放在了CPU上,也不是一直会运行的,只要是排队,一定是进程的task_struct进行排队,一个task_struct可以被连入多种数据结构中。

        所谓的状态,本质就是一个整形变量,在task_struct中的一个整形变量,状态决定了你的后续动作,Linux中可能会存在多个进程都要根据它的状态执行后续动作,一个CPU一个运行队列。

1.阻塞:

        当我们的进程在进行等待软硬件资源的时候,资源如果没有就绪,我们的进程task_struct只能1.将自己设置为阻塞状态。2.将自己的PCB连入等待的资源提供的等待队列。状态的变迁,引起的是PCB会被OS变迁到不同的队列中。

2.挂起:

        前提:计算机资源已经比较吃紧了!在操作系统中,挂起是指将一个进程或线程的执行暂时中止,并将其保存到外部存储器(如硬盘)中,以便稍后重新恢复执行。挂起通常是由操作系统或者其他进程发起的,目的是暂时释放进程或线程占用的系统资源,或者让其他优先级更高的任务先执行。

  • R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
  • S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠 (interruptible sleep))。
  • D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
  • T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
  • X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。

3.Z-僵尸进程

         僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵死(尸)进程。僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态。

僵尸进程危害:

  • 进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。父进程如果一直不读取,那子进程就一直处于Z状态。
  • 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,话 说,Z状态一直不退出,PCB一直都要维护。
  • 那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!
  • 内存泄漏。

4.孤儿进程

        父进程先退出,子进程就称之为孤儿进程,该进程转到后台,该子进程被1号进程领养,由1号进程回收。

5.进程优先级

  • cpu资源分配的先后顺序,就是指进程的优先权(priority)。
  • 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
  • 还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。

每个进程都有一些信息:

  • UID : 代表执行者的身份
  • PID : 代表这个进程的代号
  • PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
  • PRI :代表这个进程可被执行的优先级,其值越小越早被执行(默认是80)
  • NI :代表这个进程的nice值

        PRI就是程序被CPU执行的先后顺序,此值越小进程的优先级越高,而NI表示进程可被执行的优先级的修正数值,会影响到进程的优先级变化。PRI(new)=PRI(old)+nice,当nice值为负值时,该程序将会优先级值变小,优先级变高,调整进程优先级就是调整nice值,nice取值范围是-20到19.

     top命令可更改nice,进入top后按“r”–>输入进程PID–>输入nice值。

        竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。
独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。
并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行。
并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。
        进程在运行的过程中,要产生大量的临时数据,放在CPU的寄存器中。
        CPU内部的所有临时数据,我们叫做进程的硬件的上下文。
        硬件的上下文,让我们的进程进行保护,保护上下文。
        所有的保护都是为了最终的恢复,所有的恢复都是为了继续上次的运行位置继续运行。
        当进程在二次被调度的时候,进程被放到CPU上开始运行将曾经保存的硬件上下文进行恢复。
        CPU内的寄存器只有一套,寄存器内部保存的数据可以有多套。
        虽然寄存器数据放在了一个共享的CPU设备里面,但是所有的数据,其实都是被进程私有的。寄存器不等于寄存器的内容。

Linux内核进程调度队列

        一个CPU拥有一个runqueue,如果有多个CPU就要考虑进程个数的负载均衡问题,

活动队列

  • 时间片还没有结束的所有进程都按照优先级放在该队列
  • nr_active: 总共有多少个运行状态的进程
  • queue[140]: 一个元素就是一个进程队列,相同优先级的进程按照FIFO规则进行排队调度,所以,数组下标就是优先级!
  • 从该结构中,选择一个最合适的进程,过程是怎么的呢?
1. 从0下表开始遍历queue[140]
2. 找到第一个非空队列,该队列必定为优先级最高的队列
3. 拿到选中队列的第一个进程,开始运行,调度完成!
4. 遍历queue[140]时间复杂度是常数!但还是太低效了!
  • bitmap[5]:一共140个优先级,一共140个进程队列,为了提高查找非空队列的效率,就可以用5*32个比特位表示队列是否为空,这样,便可以大大提高查找效率

过期队列

  • 过期队列和活动队列结构一模一样
  • 过期队列上放置的进程,都是时间片耗尽的进程
  • 当活动队列上的进程都被处理完毕之后,对过期队列的进程进行时间片重新计算

active指针和expired指针

  • active指针永远指向活动队列
  • expired指针永远指向过期队列
  • 可是活动队列上的进程会越来越少,过期队列上的进程会越来越多,因为进程时间片到期时一直都存在的。
  • 没关系,在合适的时候,只要能够交换active指针和expired指针的内容,就相当于有具有了一批新的活动进程
  • 在系统当中查找一个最合适调度的进程的时间复杂度是一个常数,不随着进程增多而导致时间成本增加,我们称之为进程调度O(1)算法
  • 21
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值