Linux --- 系统编程阶段 ------(进程概念)

冯诺依曼体系结构

1.冯诺依曼体系:
一共由五大部分组成,分别为:输入设备,输出设备,存储器,运算器,控制器,其关系如下图所示:
在这里插入图片描述
①:其中,黑色的线表示数据的流入与流出,红色的线代表的是对各个设备的控制。中央处理器(cpu)的组成是里面有控制器和运算器,其中控制器对各个其他的设备具有控制作用。
②:数据的流入是从输入设备流入存储器中,而运算器则是对存储器的数据进行拿出来并进行运算,然后再将处理后的数据流入存储器中,最终再输出设备再从存储器中取出数据。
③:由此可以看出来,存储器是整个体系中最重要的部分,它是与其他组成部分密切相关的链接的。
2.存储器:
功能:用来存放数据和程序。
其中存储器是内存,而不是硬盘,由于在数据的处理阶段需要从存储器中拿出数据进行相应的操作,而在硬盘上取出数据的效率比低下。
总的来说是:内存而不使用硬盘作为存储器的原因是内存吞吐量大
特别的:而存储数据的时候用的是硬盘的原因是:内存中的数据是易丢失的,在断电的时候就会丢失数据,而磁盘存储数据较安全。
3.输入设备,输出设备:
功能:输入设备和输出设备都属于计算机的外部设备,主要是通过外部设备获得信息和将处理后的信息展现出来。
4.运算器:主要进行行数运算和逻辑运算,并将运算后的结果最终返回到存储器中。
5.控制器:主要用来指挥和控制程序和数据的输入运行,以及处理运算结果。
不考虑缓存的情况,其中cpu只能对内存上的数据进行读写,不能访问外设(输入、输出设备)。

操作系统

1.操作系统的概念:
任何一个计算机系统,都包含一个基本的程序集合,被成为操作系统(OS)。(实际上就是一个软件,用来管理计算机上的软硬件资源)
2.操作系统的内容:
①:内核(进程管理,内存管理,文件管理,驱动管理)
②:其他程序(如:函数库、shell等等)
3.设计的目的:
①:主要是为了管理计算机上的软硬件资源。
②:为了让用户的程序拥有一个良好的执行环境。
4.管理方式为:
①:描述被管理的对象。
②:组织被管理的对象。
5.其在计算机中的管理的分布图如下:
在这里插入图片描述
其中:
①:系统调用接口:操作系统向用户提供的可以访问内核的接口
②:shell外壳等其他指令:针对一些典型的接口进行封装。
库函数封装了系统调用接口。(库函数指的是shell外壳那行)

进程概念

1.进程的基本概念:
①:在用户的角度:正在运行的程序。
②:在操作系统的角度:是程序运行的动态描述(pcb),其中包含程序运行的各项信息,实现操作系统对于运行中的程序的管理(正在担当分配系统资源(cpu时间,内存)的实体)。
2.程序的基本概念:
①:程序:软件----程序员所写的代码,保存在磁盘中。
②:程序运行:基于冯诺依曼体系,首先将程序从磁盘加载到内存中,然后进行如下图操作:
在这里插入图片描述
其中,每个进程都有一个pcb,而cup对正在运行的进程是通过pcb来去管理的,但是同时很多进程都在运行,那么cpu是如何进行管理的呢,pcb到底是什么呢?如下:
①:cpu的管理机制为分时管理机制:就是让每个进程都会在cpu上去运行很短的一段时间(时间片),切换运行。
②:pcb本质上是一个结构体,被装载在cpu里面,其中包含了一个进程的许多信息,如:标识符—PID(进程id),内存指针,程序计数器,上下文数据,进程状态,进程优先级,IO状态信息,记账信息等。

进程状态

1.进程状态的概念:描述该进程目前处于什么状态,应该如何被操作系统调度管理。
①:状态一般分为:就绪,运行,阻塞。
②:在linux可以被表示的状态分为以下几种:

  • R(运行态):代表进程要么正在运行的,要么就在等待运行的队列里面。
  • S(休眠态):代表进程在等待事件结束。(代表可以被打断的阻塞状态,也可叫可中断休眠态)
  • D(磁盘休眠态):代表不可被打断的阻塞状态,一般情况下会等待IO结束,也可叫不可中断休眠态。
  • T(停止态):停止运行,但是还是占cpu(可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT信号让进程继续运行)。
  • X(死亡态):这个状态只是一个返回状态,在进程运行时看不见。
  • Z(僵尸态):程序退出后的中间等待处理状态。

其中这些状态的关系可以如下图所示:

在这里插入图片描述
2.僵尸进程:
①:产生:子进程先于父进程退出。此时子进程为了确保自己退出的返回值,因此没有完全释放资源,而是等待父进程处理。
②:危害:退出后的资源没有被完全释放的进程。会导致资源泄漏其中包括有内存泄漏和进程数量的占有。
③:避免:进程等待。
④:处理:退出父进程。
特别的与僵尸进程对应的还有一个孤儿进程
①:产生:父进程先于子进程退出。
②:特点:子进程运行在后台,并且子进程的父进程变为1号进程,并且孤儿进程退出后,也不会成为僵尸进程。
③:并且其可以制造出来守护进程(精灵进程):就是在后台可以一直稳定运行的进程,并且与终端脱离了关系,(不受任何终端控制)。
④:守护进程的创建方式:当子进程成为孤儿进程的时候,对其使用(setsid()函数)进行建立新的会话。
3.查看进程的指令:
①:查看指令:ps
语法:ps [选项]
功能:查看进程此时的各种信息。
选项:
-ef :查看所有进程的状态信息。
-aux:查看所有进程状态的详细信息。
如下图分别为-ef和-aux的状态信息:
-ef如下:
在这里插入图片描述
-aux如下:
在这里插入图片描述
其中aux展示的比较详细,但是aux并没有展现当前进程的父进程。
②:删除指令:kill
语法:kill 指令id
功能:删除该指令
4.创建进程:
①:使用函数 :pit_t fork(void)
②:其中pit_t为一个数据类型,其返回的数值一般情况下为大于0,等于0,小于0;
③:其中当返回值大于0的时候,证明该返回值为其父进程所接收的,所以大于0的时候父进程运行该段代码,等于0的时候为子进程运行的地方,小于0说明,子进程创建失败。
④:一般情况下是大多是通过if语句来让父子进程干不同的事情。

环境变量

1.基本概念:一般指在操作系统中,用来指定操作系统运行环境的一些参数。(保存程序运行环境的变量)
2.作用:在进程之间传递一些数据。
3.常见的环境变量:

  • PATH:指定命令的搜索路径(程序运行默认运行路径。(意思为,如果将可执行程序加入到该路径中,即便是不加./也可以运行))
  • HOME:指定用户的主工作目录
  • SHELL:当前Shell,通常是/bin/bash

4.环境相关的指令:
①:env:查看所有环境变量(不可查看普通的变量)
②:set:查看环境中的所有变量(既可以查看环境变量,也可也查看普通变量)
③:echo:打印某个指定变量的数据。(其中变量名需要用${NAME},NAME为环境变量名称)
④:export:用于声明环境变量(自己创建一个环境变量)
语法:export 变量名=数值
⑤:unset:删除环境变量(普通变量也可也通过该指令删除)
5.环境变量的组织方式:
每个程序都会得到一个环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’为尾的环境字符串。
其表示图如下:
在这里插入图片描述
6.通过系统调用获得或者设置环境变量:
可以使用下面这个函数:

char *getenv(char* name);

其中name是环境变量的名称,返回值为对应name环境变量的数据地址。

程序地址空间

1.首先我们看下面这个图,表示的是内存条上的各个数据模块的分布(我们以4G内存为例):
在这里插入图片描述
如图就是分布情况。
2.存在的问题:进程在内存条上的存储位置不确定,我们看如下代码:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int val = 0;
int mian()
{
   pit_t pid = fork();
   if(pid < 0)
   {
      printf("prror pid\n");
   }
   else if(pid == 0)
   {
      printf("This is Child %d : %p\n",val,&val);
   }
   else
   {
      printf("This is parent %d : %p\n",val,&val);
   }
   return 0;
}

执行结果如下图:
在这里插入图片描述
没有什么问题,但是但当我们将子函数中的val进行修改的时候,我们会得到如下答案:
代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int val = 0;
int mian()
{
   pit_t pid = fork();
   if(pid < 0)
   {
      printf("prror pid\n");
   }
   else if(pid == 0)
   {
      val = 100; 
      printf("This is Child %d : %p\n",val,&val);
   }
   else
   {
      printf("This is parent %d : %p\n",val,&val);
   }
   return 0;
}

执行结果如下图:
在这里插入图片描述
可以看到,val的地址是相同的,但是相同的地址,怎么会出现不同的变量呢?所以我们推出了虚拟地址。
3.虚拟地址:
①:由上可以看出,操作系统给,每个进程都虚拟了一个完整的地址空间,如下图:
在这里插入图片描述
父进程和子进程都有一个虚拟地址空间,而val都在虚拟地址空间的相同位置,而映射到物理地址的时候,便是不同的位置,这样就造就了相同的位置,但是获得的数是不同的结果。
②:其实情况是这样的,操作系统给每个进程虚拟了一个独立的完整的虚拟地址空间,让每个进程都可以去访问自己的独立的连续的虚拟地址,但是实际的数据存储可以经过映射后,存储在物理内存的任意位置,这个位置是不连续的,这样就实现了数据在物理内存上的离散式存储。
而离散式存储大大提高了内存的利用率。
4.虚拟地址空间其实就是一个地址空间描述,本质上就是一个结构体,在底层的名字叫做struct mm-struct。
所以程序地址空间就是这样的:
本质上就是操作系统为进程通过mm-struct描述虚拟地址空间,让每个进程都能访问一个独立的完整的连续的虚拟地址,给过映射之后,是现在物理内存上的离散式存储,提高内存的利用率,提高内存访问控制。
5.如何通过虚拟地址找到物理内存中的存放位置呢?
其实在内部一共有三种内存的管理方式,分别如下:
①:分段式:将虚拟地址空间分成多个段,分段式管理会给每个进程创建段表。
而他们的分布如下:
在这里插入图片描述

通过虚拟地址的段号在段表中找到物理地址。
使用方法:取出虚拟地址里面的段号,在段表中通过段号找到段表项,取出物理地址的起始位置,加上段内的偏移量,就可以得到某个变量在物理地址的具体存储位置。
段内偏移量:就是相对于起始位置的数量。
②:分页式内存管理:
它的管理图如下:
在这里插入图片描述
在虚拟地址空间中将整个空间划分为一个个小的分页(一个分页通常有4096字节)。
缺页中断:通过虚拟地址获取物理地址进行访问地址内存的时候,数据不在内存中。
产生的原因:物理内存通常都不大,运行程序多了,总会有内存不够的时候,当内存不够的时候会产生内存置换。
内存置换:将物理内存中的不活跃的数据写入到磁盘中保存起来,然后将原位置改为新加载的数据。
而与分段式的比较:
分段式:是将虚拟地址空间进行分段管理,对内存的利用率并没有太大提高,但是对程序的地址管理比较好。
而分页式:将虚拟地址空间分成一个个小小的页面进行管理,实现了离散式存储,提高了内存利用率,并且在页表中进行了权限管理,提高了内存访问控制。

③:段页式管理:
将虚拟地址空间先进行分段管理,然后在每个短萼你进行分页式管理,集合了分页和分段的优点。
其中地址中包含:段号,段内页号,业内偏移。

  1. 通过段号在段表中找到段表项
  2. 在段表项中找到段内页表地址
  3. 通过段内页号在段内页表中找到页表项
  4. 通过页表项中的物理块起始地址加上页内偏移,得到物理地址。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值