操作系统与进程(1)

简介: 操作系统与进程(1)

文章目录

冯诺依曼体系结构

冯诺依曼体系结构

1.输入设备:键盘,磁盘(外设,读取文件(没读的时候就在磁盘)),网卡,显卡,话筒,摄像头(效率是s,ms级别)

2.输出设备:显示器,打印机,磁盘(写文件,就是把数据写到磁盘上),网卡,显卡,音箱等

3.存储器(内存):离cpu越近的设备存储效率越高也越贵,有了内存,cpu就不用直接和外设打交道,存储器的快慢决定快慢(内存是体系结构的核心设备)

4.运算器&&控制器(CPU):运算器(算术运算与逻辑运算)

控制器(读取指令,分析指令,执行指令)(效率ns级别)


a和b通过qq发消息


任何的外设,在数据层面,基本都是有限和内存打交道!,

cpu,在数据层面上,也直接和内存打交道

操作系统

启动的(将软件数据与代码,加载到内存中)操作系统,才有意义


是什么

OS 是一款软件,专门针对软硬件资源进行管理工作的软件

(核心工作就是做管理的)


为什么

对下:管理好软硬件资源。对上:给用户提供稳定高效安全的运行环境

方式 目的


怎么办

核心在管理,管理是对人的属性数据进行管理,描述属性结合的就是结构体,里面就有被管理者的全部数据,再加个联系指针连接起来(链表,哈希,树等),对学生的管理就变成了对链表的管理,对学生的褒奖工作就变成了对链表的增删查改


本质(先描述再组织)

管理理念:先描述,再组织,

可以转化成对目标的管理,

转化成对数据的管理

进程(软件)

加载到内存的程序就叫做进程

系统中可能存在大量的进程,操作系统要管理进程

如何管理进程?

先描述,再组织

任何进程在形成的时候,操作系统要为该进程创建PCB,进程控制块( 先描述,struct PCB 里面就是进程的所有属性,结构体描述),

PCB

OS 上面,PCB 进程控制块,就是一个结构体类型

在Linux系统中,PCB ->struct task_struct{ //进程的所有属性 }

类比shell和bash的关系

类比媒婆和王婆的关系

我们所有启动的程序的过程都是在系统上面创建进程

把程序运行起来,就是把程序加载到内存,就是把程序由磁盘加载到内存中变成一个进程

进程的属性

程序运行结束进程就结束了

进程vs程序

有了进程控制块,所有进程管理任务与进程对于的程序毫无关系!!!

与进程对应的内核创建的进程的 PCB 强相关

进程=程序+操作系统维护进程的相关数据结构(更多的数据结构)(进程控制块)

PCB的内部构成

  • pid:描述本进程的唯一标识符,原来区别其他进程

结束进程

kill -9 pid

  • ppid:获得其父的pid(在命令行上运行的命令,基本上其父进程都是-bash)

状态:任务状态,退出代码,退出信号等。

0

输出离他最近执行命令的退出码


优先级:相对于其他进程的优先级,CPU 只有1个,进程有非常多个,确认先后的问题,


程序计数器:程序中即将被执行的下一条指令的地址


内存指针:可以通过PCB 找到对应的代码和数据


IO状态信息:进程可能要进行的IO,(从输入设备读入)(输出设备读出),进程在进行IO,


记账信息:进程被os调度器调度的信息(os为了较为均衡的调用每个进程(获得cpu的资源(进程被执行))),有处理器时间总和,使用的时间限制,记帐号


上下文数据:(进程执行时处理器的寄存器中的数据)寄存器(当前正在运行的进程的临时数据)

时间片(单次运行每个进程的最大时间10ms,没跑完,排到最后等待继续运行),在cpu情况下,用户感受到多个进程都在运行(靠cpu快速切换完成的),进程在运行期间是由切换的,进程可能存在大量的临时数据----》暂时在cpu的寄存器中保存,

保护上下文

恢复上下文

虽然寄存器硬件只有一份,但是寄存器里面的数据是你这个进程的,走的时候,把寄存器里面的数据返回pcb里面,进入下一个进程,等待下一次使用,再进入时,再把之前的临时数据放回cpu

通过上下文的保护和恢复,我们可以感受到进程被切换的

查看进程的方案

ls /proc

exe就是当前执行的文件路径

cwd就是当前工作路径

fork

fork就是用来创建子进程的


演示

1 #include <iostream>
  2 using namespace  std;
  3 #include<unistd.h>
  4  
  5 int main()
  6 {                                                                 
  7     fork();//创建子进程
  8     cout<<"hello proc "<<getpid()<<"hello parent "<<getppid()<<endl;
  9     sleep(1);                                                                                   
 10     return 0;                                                                                    
 11 }    

上面的代码我们fork后,只写了一行的打印,但是运行结果是有两条的内容

如何理解fork创建子进程

有我们在命令行里面./cmd or run command(执行指令) ,与fork相比:在操作系统角度上,创建进程的方式都是没有差别的,只不过fork创建的进程间有父子关系


fork本质是创建进程 ----> 系统里面多了一个进程 —>在系统里面多了一份与进程相关的内核数据结构 (task_struct) + 进程的代码和数据(我们只是fork了,创建了子进程,但是子进程对应的代码和数据)---------》


默认情况下,会继承父进程的代码和数据

内核数据结构task_struct 也会以父进程为模板,初始化子进程的task_struct

例如父亲是做鞋的工厂老板,那么你就会继承父亲的基因(数据结构),同时你也会子承父业继续做鞋(继承代码和数据)


进程具有独立性


代码

fork之后子进程和父进程代码是共享的

代码是不可以被修改的

父子代码只有一份

数据

默认情况下“数据也是共享的”,不过因为进程具有独立性,所以也要考虑修改的情况

可以通过“写时拷贝”来完成进程数据的独立性

fork的返回值

我们创建的子进程,就是为了和父进程干一样的事情???

一般是没有意义的,我们一般还是希望要让父进程和子进程做不一样的事

我们通常是用fork的返回值来完成

  • 失败: <0
  • 成功:
  • 给父进程返回子进程的pid
  • 给子进程返回0
 1 #include <iostream>                                                       
  2 using namespace  std;             
  3 #include<unistd.h>  
  4 #include <sys/types.h>  
  5 int main()  
  6 {  
  7     pid_t id=fork();//获得其返回值 
  8     cout<<"hello proc "<<getpid()<< " hello parent "<<getppid()<<" ret: "<< id <<endl;  
  9     sleep(1);                                                                                            
 10     return 0;                                                                      
 11 }    

如何理解有两个返回值?

如果一行函数已经执行return,那么函数的核心功能执行完了

pid_t fork()
{
//创建子进程的逻辑
 return XXX;//也是语句,父子共享return
}


到return的时候,他创建子进程的逻辑也完了,所以子进程已经有了,父进程要return,子进程也要return


返回的是数据吗?return的时候也会写入吗?


返回的也是数据,会,发生了写时拷贝


如何理解两个返回值的设置


父:子=1:n,


子进程的父进程只有1个,而父进程可以有很多的子进程,所以要得到其子进程的pid来控制子进程,而子进程通过ppid就可以找到父进程

对多进程的控制

#include<iostream>
#include<unistd.h>
using namespace std;
int main()
{
    pid_t id=fork();
    if(id==0)//利用if else,进行分流,实现父子进程完成不同的事
    {
//child
        while(true)
        {
      cout<<"I am 子进程 pid="<<getpid()<<" ppid="<<getppid()<<endl;
            sleep(1);
        }
    }
    else if(id>0)
    {
    while(true)
        {
      cout<<"I am 父进程 pid="<<getpid()<<" ppid="<<getppid()<<endl;
            sleep(2);
        }
    }
    else
    {
    //todo
    }
    sleep(1);
    return 0;
}

fork之后谁先跑呢??

不确定

进程状态

进程的状态信息在哪里呢??

在 task_struct(PCB)

进程状态的意义:

方便OS 快速判断进程,完成特定的功能,比如调度,本质是一种分类具体的状态

R:运行态,不一定正在CPU上面正在运行,但是如果处于运行的队列(等待CPU)中,那么这些状态都可以称为R状态,随时都可以被CPU进行调度


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p20zfQoB-1647504125418)(picture/image-20220310140329017.png)]


S/D:睡眠状态,当我们想要完成某种任务的时候,任务条件不具备,需要进程进行某种等待时,就S,D,等待资源就绪


如:今天想打游戏,但是电脑没开,那么我们就要开机等待电脑开机,那么此时我们就是S,D


所谓的进程,在运行的时候可能会因为运行的需要,可以会在不同的队列里,


在不同的队列里面,所处的状态是不一样的


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3K13Q8eR-1647504125419)(picture/image-20220310141732027.png)]


如果资源就绪了那么S状态就变成了R状态,放到运行队列里,


如果这个进程突然卡死了,那OS就会把他从运行队列放到等待队列里面去


我们把,从运行状态的task_struct(run_queue),放到等待队列中,就叫做挂起等待(阻塞)


从等待队列,放到运行队列,被CPU调度,就叫做唤醒进程

#include<iostream>
#include<unist.h>
int main()
{
    sleep(10);
    cout<<"hello "<<endl;
return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0vxSbIJj-1647504125420)(picture/image-20220310144349978.png)]


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uAi5lsGD-1647504125420)(picture/image-20220310143310732.png)]


等待我们设定的10s就绪,那么他就处于S状态,


可以直接立即终止(可中断睡眠)


深度睡眠 ;不可中断睡眠,


假设进程发出了一个命令,要将1t数据(数据量非常大)都放到磁盘里面,让磁盘去读写,之后磁盘就开始工作了,这个时候进程就开始等待


等待磁盘把任务完成,这个时候,OS来了发现进程在休息,就把他给杀掉了,


磁盘读写完了,要把失败与否的结论告诉进程,但是发现进程不见了,


进程:是OS把我杀掉的


磁盘:是进程不见的


没有办法解决问题


本质上是因为操作系统把正在等待的进程给杀掉的


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JH3pVRNg-1647504125421)(picture/image-20220310153558797.png)]


所以为了解决这个问题,就有了深度睡眠的D状态,

进程进入了D状态,不可被杀掉


T :暂停状态,完全暂停不会因为某种条件达成变成R,做某些任务的时候,进程需要暂停


t(trace stop):经常调试程序的时候,在调试的时候,进程所处的状态,打个断点,就停下来了,临时查看很多资源数据


x(dead):死亡状态,回收进程资源=进程相关的数据结构+你的代码和数据(和创建的操作是一样的),死亡状态无法查到


z(zombie):僵尸状态,先进入僵尸状态再进入死亡状态


为什么要有僵尸状态


为了辨别退出死亡原因,进程退出时要暂时保存退出的信息


在task_struct存了进程退出的所有信息


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VWpdwoVG-1647504125421)(https://raw.githubusercontent.com/zevin02/image/master/%20202203121022560.png)]

状态代码验证

R

:没有IO ,所以就不用等待

  1 #include<iostream>
  2 using namespace std;
  3 int main()
  4 {
  5     while(true);
  6     return 0;                                                                                            
  7 }

S

  1 #include<iostream>
  2 using namespace std;
  3 int main()
  4 {
  5     while(true)
  6     {
  7        cout<<"hello"<<endl;
  8     }                                                                                              
  9     return 0;         
 10 }                     
~         

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RYSD1QuG-1647504125422)(https://raw.githubusercontent.com/zevin02/image/master/%20202203111201188.png)]



[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w6blxo0h-1647504125423)(https://raw.githubusercontent.com/zevin02/image/master/%20202203121024675.png)]


有可能还能检测到r状态


打印,是往显示器打印,外设慢,IO,实际上等待外设就绪是很慢的,所以大部分状态都是S状态,CPU太快了


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NWVrfyha-1647504125423)(https://raw.githubusercontent.com/zevin02/image/master/%20202203121028603.png)]


暂停进程

继续进程

后面没有+号,在后台运行

但是按ctrl c无法结束进程

结束进程

+

:带了+,说明是在前台运行,在命令行输入任何内容都是没有用的,但是ctrl c来干掉进程


后台进程./myproc &,就变成后台进程,可以在命令行中输入命令,无法用ctrl c来结束进程,只能用kill -9 pid来结束进程


z

如果没有人检测回收进程(父进程),该进程退出或进入z

1 #include <iostream>                                                                                
  2 #include<unistd.h>
  3 using namespace std;
  4 int main()                                       
  5 {                 
  6     pid_t id=fork();
  7     if(id==0)
  8     {                 
  9        //child       
 10        while(true)
 11       {                
 12          cout<<"I am child,running"<<endl;
 13           sleep(2);
 14        }                                   
 15     }                                       
 16     else           
 17     {  
 18        //father
 19        cout<<"I am father ,doing nothing"<<endl;
 20        sleep(50); 
 21     }  
       return 0;
 22 }

子进程给终止掉,但是父进程没有回收,就变成了僵尸进程

(子进程先死了,父进程还在运行)

孤儿进程

被1号进程领养,1号进程也叫做操作系统OS

父进程终止了,子进程还在运行

  1 #include <iostream>                                                                                
  2 #include<unistd.h>
  3 using namespace std;
  4 int main()                                       
  5 {                 
  6     pid_t id=fork();
  7     if(id==0)
  8     {                 
  9        //child       
 10        while(true)
 11       {                
 12          cout<<"I am child,running"<<endl;
 13           sleep(2);
 14        }                                   
 15     }                                       
 16     else           
 17     {  
 18        //father
 19        cout<<"I am father ,doing nothing"<<endl;
 20        sleep(10);
     exit(-1);
 21     }  
       return 0;
 22 }

进程优先级

为什么会有优先级?

本质上是资源太少的问题,优先级本质是获得资源,分配资源的一种方式

查看进程的方案

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 int main()
  4 {
  5   while(1)
  6   {
  7   ¦ printf("I am a process ,pid %d,ppid %d\n",getpid(),getppid());                           
  8   ¦ sleep(1);
  9   }
 10   return 0;
 11 }
~

UID 相当于我的名字,不过他是以数字来标识(类似身份证号码)

PRI就是优先级数据

NI优先级的修正数据,

linux中的优先级数据,值越小,优先级越高,


就尽快的享受到某种资源


PRI vs NI


加入nice值,PRI(new)=PRI(old)+nice


所以nice为正,优先级变满,


反之亦然


特别不建议自己修改优先级


优先级设置

nice值(-20~19)

old不会因为之前的改变而改变,还是一开始的值

nice值为什么是一个相对小的范围

优先级再怎么设置,也只能是一种相对的优先级,不能出现绝对的优先级,避免有的进程出现饥饿问题,而我们的调度器

就是为了较为均衡的让每个进程享受到CPU资源,

相关文章
|
1月前
|
算法 Linux 调度
深入理解Linux操作系统的进程管理
本文旨在探讨Linux操作系统中的进程管理机制,包括进程的创建、执行、调度和终止等环节。通过对Linux内核中相关模块的分析,揭示其高效的进程管理策略,为开发者提供优化程序性能和资源利用率的参考。
82 1
|
2月前
|
算法 调度 Python
深入理解操作系统中的进程调度算法
在操作系统中,进程调度是核心任务之一,它决定了哪个进程将获得CPU的使用权。本文通过浅显易懂的语言和生动的比喻,带领读者了解进程调度算法的重要性及其工作原理,同时提供代码示例帮助理解。
|
1月前
|
调度 开发者 Python
深入浅出操作系统:进程与线程的奥秘
在数字世界的底层,操作系统扮演着不可或缺的角色。它如同一位高效的管家,协调和控制着计算机硬件与软件资源。本文将拨开迷雾,深入探索操作系统中两个核心概念——进程与线程。我们将从它们的诞生谈起,逐步剖析它们的本质、区别以及如何影响我们日常使用的应用程序性能。通过简单的比喻,我们将理解这些看似抽象的概念,并学会如何在编程实践中高效利用进程与线程。准备好跟随我一起,揭开操作系统的神秘面纱,让我们的代码运行得更加流畅吧!
|
11天前
|
监控 搜索推荐 开发工具
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
2025年1月9日更新Windows操作系统个人使用-禁用掉一下一些不必要的服务-关闭占用资源的进程-禁用服务提升系统运行速度-让电脑不再卡顿-优雅草央千澈-长期更新
|
1月前
|
C语言 开发者 内存技术
探索操作系统核心:从进程管理到内存分配
本文将深入探讨操作系统的两大核心功能——进程管理和内存分配。通过直观的代码示例,我们将了解如何在操作系统中实现这些基本功能,以及它们如何影响系统性能和稳定性。文章旨在为读者提供一个清晰的操作系统内部工作机制视角,同时强调理解和掌握这些概念对于任何软件开发人员的重要性。
|
1月前
|
Linux 调度 C语言
深入理解操作系统:从进程管理到内存优化
本文旨在为读者提供一次深入浅出的操作系统之旅,从进程管理的基本概念出发,逐步探索到内存管理的高级技巧。我们将通过实际代码示例,揭示操作系统如何高效地调度和优化资源,确保系统稳定运行。无论你是初学者还是有一定基础的开发者,这篇文章都将为你打开一扇了解操作系统深层工作原理的大门。
|
1月前
|
存储 算法 调度
深入理解操作系统:进程调度的奥秘
在数字世界的心脏跳动着的是操作系统,它如同一个无形的指挥官,协调着每一个程序和进程。本文将揭开操作系统中进程调度的神秘面纱,带你领略时间片轮转、优先级调度等策略背后的智慧。从理论到实践,我们将一起探索如何通过代码示例来模拟简单的进程调度,从而更深刻地理解这一核心机制。准备好跟随我的步伐,一起走进操作系统的世界吧!
|
1月前
|
算法 调度 开发者
深入理解操作系统:进程与线程的管理
在数字世界的复杂编织中,操作系统如同一位精明的指挥家,协调着每一个音符的奏响。本篇文章将带领读者穿越操作系统的幕后,探索进程与线程管理的奥秘。从进程的诞生到线程的舞蹈,我们将一起见证这场微观世界的华丽变奏。通过深入浅出的解释和生动的比喻,本文旨在揭示操作系统如何高效地处理多任务,确保系统的稳定性和效率。让我们一起跟随代码的步伐,走进操作系统的内心世界。
|
1月前
|
运维 监控 Linux
Linux操作系统的守护进程与服务管理深度剖析####
本文作为一篇技术性文章,旨在深入探讨Linux操作系统中守护进程与服务管理的机制、工具及实践策略。不同于传统的摘要概述,本文将以“守护进程的生命周期”为核心线索,串联起Linux服务管理的各个方面,从守护进程的定义与特性出发,逐步深入到Systemd的工作原理、服务单元文件编写、服务状态管理以及故障排查技巧,为读者呈现一幅Linux服务管理的全景图。 ####
|
2月前
|
算法 Linux 调度
深入浅出操作系统的进程管理
本文通过浅显易懂的语言,向读者介绍了操作系统中一个核心概念——进程管理。我们将从进程的定义出发,逐步深入到进程的创建、调度、同步以及终止等关键环节,并穿插代码示例来直观展示进程管理的实现。文章旨在帮助初学者构建起对操作系统进程管理机制的初步认识,同时为有一定基础的读者提供温故知新的契机。