Linux 进程的概念

 操作系统是什么?

操作系统=操作系统内核 + 一堆应用

任何计算机系统都包含一个基本的程序(一堆代码)集合,称为操作系统(OS)

操作系统内核 : 也是代码程序,代码的作用(内存管理,文件管理,驱动管理等等)

一堆应用:依附在操作系用内核上完成某些功能的软件,例如:微信,飞书等等

操作系统在做什么事情?

管理计算机软硬件资源

软件资源:进程资源 驱动程序 等等

硬件资源:cpu 内存 硬盘 网卡 显示器 等等

操作系统怎样完成这些事情呢?

通过管理

管理=描述(结构体)+组织(链表)


我们站在代码的角度来看就是:结构体 + 链表

类似这样

 操作系统组织结构图

系统调用&&库函数

系统调用 : 操作系统提供的函数,被称为系统调用函数

库函数 : C标准库中提供的函数被称为库函数   (例如 strcpy memcpy printf strncpy)

 

系统调用函数有大量参数,极其不方便使用

于是大佬程序员写了库函数 (为一些系统函数参数设置默认值)方便我们使用

1 进程概念(PCB)processing control block

   

1.1什么是进程什么是程序

程序:源代码经过编译产生的可执行文件, 这个文件是静态的。
进程:程序运行起来的实例, 是动态在运行的。

1.2描述(PCB) (struct  task_struct {...})

进程标识符:在当前机器能够唯一表示一个进程

进程号(PID)

ps aux | grep [./可执行文件的名字]

ps -ef | grep [./可执行文件的名字]

getpid();//(在代码中使用)

PID :当前进程号  PPID :当前进程父进程id

 

1.3进程状态 三大状态(就绪/运行/阻塞/)

机器当中有很多进程但是cpu个数远少于进程那么进程如何获得cpu资源

void main(){

printf("hello cpp");
}

//进程要运行必须获得cpu资源(执行代码)

操作系统调度进程获得cpu资源

调度策略:
  
   先来先服务
   短作业优先
   长作业优先
   优先级优先
   时间片轮转
   多级反馈队列
运行: 进程占用CPU 并在CPU上运行; 理解为进程正在使用cpu来执行自己的代码

就绪:进程已经具备运行条件,但是CPU还没有分配过来;理解为进程已经将运行前的准备工作
全部做好了, 就等着操作系统调用占用CPU了

阻塞:进程因等待某件事发生而暂时不能运行;例如: 等待IO输入,调用某些阻塞接口;

(比如你这个进程运行过程中需要打印机但是打印机目前被占有,cpu是高速设备
它不会和你一起等打印机,而是把你阻塞起来让你自己等,等你等到了
再将你这个进程由阻塞态转化为就绪态等待分配cpu资源)

 进程的执行是抢占式的

在机器的CPU数量少,进程多的情况下(常态) 操作系统在调度的时候要做到雨露均沾。
让每一个进程都能运行

上,但是操作系统在调度的时候,是从就绪队列当中获取进程, 进行运行。 换句话说, 进程谁准备好了,
谁就绪了,原则上就可以调度谁。所以,进程为了能执行自己的的代码,都是抢占式执行,不会互相谦让。

所以进程就会有不同的状态, 其中之一原因就是“狼多肉少”

操作系统调度的时候有各种算法:短作业优先,先来先服务,
高优先级优先,时间片(毫秒级别: 5-800) 轮转等等

 并发与并行

并发:多个进程在一个CPU下,采用进程切换的方式,各自独占CPU运行各自的代码, 交替运行,让多个进程都得 

以推进,称之为并发并发

并行:多个进程在多个cpu下,同时运行各自的代码,称为并行

 

 进程的状态

细分的进程状态:

R:运行状态 (代码)
处于R状态的进程, 有可能在执行代码, 有可能在运行队列(就绪队列)

S:可中断睡眠状态(代码)
进程正在睡眠(被阻塞),等待资源到来是唤醒,也可以通过其他进程信号或时钟中断唤醒,进入运行队列

D:不可中断睡眠状态: 通常等待一个I/O结束(也就是输入输出结束)

T:暂停状态 (ctrl+z) (代码)
结论: 在linux下不要使用ctrl+z结束进程,不是结束,而是暂停       ctrl+c可以终止一个进程

t:跟踪状态 :
调试程序的时候可以看到

X:死亡状态 :
这个状态是用户看不到的,在PCB被内核释放的时候进程会被置为X,紧接着进程就退出了

Z:僵尸状态
程序计数器:保存程序下一条执行的指令
上下文信息:保存寄存器当中的内容

在多进程操作系统中,操作系统调度进程,获取cpu后进行恢复现场(上下文信息)继续执行后面的代码


//雪糕是甜的 果啤也是甜的,先吃雪糕后喝果啤会产生落差感 ,让你觉得果啤是苦的

描述(PCB)

struct task_struct{

   进程标识符(进程号)
   进程状态
   程序计数器
   上下文指针
   内存指针:指向“程序地址空间”
   记账信息: 使用CPU时长, 占用内存大小
   I0信息: 保存进程打开文件的信息
   /proc/[pid] : 进程存在于磁盘的文件信息一个进程是一个以pid命名的文件

}


//只是冰山一角

 组织

 创建子进程

1.fork


    #include <unistd.h>
   pid_t fork(void);


作用: 让一个正在运行的进程调用该函数,可以让运行的进程创建出来一个子进程。 两者是父子关系
参数: 没有参数

2.fork()的返回值
失败:返回-1
成功:返回两次,父进程返回大于0的数字(子进程的pid), 子进程返回等于0

 

创建子进程原理

子进程拷贝父进程的PCB

结论:

1.父子进程代码共享,因为子进程拷贝PCB,所以拥有相同的代码

2.数据独有(栈区的数据 , 堆区的数据)因为各自有各自的程序地址空间

3.父进程将子进程创建出来之后,子进程就是一个独立的进程,
被操作系统独立调度(与父进程没有半毛钱关系)并且父子进程抢占式运行

 

父子进程虽然数据独立但是代码段却一样,请问子进程被创建后是怎样执行的?

虽然子进程都是拷贝父进程的资源,但是在代码执行时子进程是从是从fork();之后执行的
若从main()或者fork()之前就会出现递归的创建子进程

子子孙孙无穷尽,程序直接崩溃

 僵尸进程

 

 

为啥叫僵尸进程呢

前提命令 kill [pid] :强杀一个进程

但是僵尸进程无法强杀(僵尸:已经死了怎样杀)
产生原因:
    子进程先于父进程退出,子进程在退出时,告知父进程(信号),
父进程进行了忽略处理,父进程没有回收子进程的退出状态信息,从而导致子进程变为僵尸进程
僵尸进程的危害

子进程的资源是由父进程来回收的

子进程的PCB(struct task_struct{})未被操作系统内核释放,从而导致内存泄漏
怎样处理僵尸进程

1.终止其父进程

2.重启操作系统

3.进程等待

孤儿进程

产生原因:

父进程先于子进程退出,子进程变成了孤儿进程

模拟产生孤儿进程

1号进程 操作系统的init进程 操作系统的很多进程由该进程创建

孤儿进程的父进程变成1号进程,也就意味着孤儿进程退出时,
退出状态信息由1号进程回收

孤儿进程有危害吗?

无  进程退出状态信息由1号进程回收
有孤儿进程无孤儿状态

环境变量

什么是环境变量

环境变量是指在操作系统中用来指定燥作系统运行的一些参数:换句话说, 
操作系统通过环境变量来找到运行时的一些资源,例如:链接的时候,
 帮助链接器找到动态库(标准库的) ;(用户自己编译的动态库,需要自己指定环境变量)
执行命令的时候,帮助用户找到该命令在哪一个位置,例如ls

env 查看当前目录环境变量

echo $[环境变量名称]
//查看单个环境变量对应的值

 

环境变量对应的文件
    系统级文件:针对于各个用户都起作用(root用户修改),强烈不推荐修改系统级的环境变量文件,
因为会影响其他用户



用户级别环境变量文件:推荐大家修改这两个文件,只对自己用户的环境变量做出修改,影响自己



~/.bashrc
~/.bash profile

~/.bash profile包含~/.bashrc包含/etc/bashrc

zyb:
    ~/.bash profile
       ~/.bashrc
          /etc/bashrc

修改环境变量

export 环境变量名称=[$环境变量名称]:[新添加内容]
//这样写会保存之前的环境变量,所以是添加

export 环境变量名称=[修改内容]
//这样写会修改环境变量为修改内容,之前的环境变量就没有了

命令行中修改是临时生效

文件中修改不会立即生效  需要配合source[环境变量文件名称],永久生效

 环境变量组织方式

 

 用代码获取环境变量

 

environ 

extern char **environ 这个是全局外部变量在c标准库中定义,需要用extern关键字

 

getenv(["环境变量名"])
#include <stdlib.h>
char *getenv(const char *name)
参数: 环境变量名称
返回值:环境变量的值,没找到返回NULL

 

 虚拟地址

变量内容不一样,所以父子进程输出的变量绝对不是同一个变量

但地址值是一样的,说明,该地址绝对不是物理地址!

在Linux地址下,这种地址叫做虚拟地址

 为啥操作系统费劲的要搞出来一个虚拟地址呢 ?

提高内存利用率

 

虚拟地址
我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,
由OS统一管理OS需要负责将程序当中的虚拟地址,转化为物理地址
4.进程虚拟地址空间
操作系统为每一个进程虚拟出来一个4G的虚拟地址空间(32位操作系用),
 程序在访问内存的时候,使用的是虚拟地址进行访问

既然是操作系统虚拟出来的地址, 所以并不能直接存储数据, 
存储数据还是在真实的物理内存当中。
所以OS需要将虚拟地址转化为物理地址进行访问(页表)
为什么操作系统需要给每一个进程都虚拟出来个进程地址空间呢?
为啥不直接让进程访问物理内存,这样不是更加快一点?




原因: 因为各个进程访问同一个物理地址空间,就会造成不可控。在有限的内存空间中,  
进程是不清楚哪一个内存被其他进程使用, 那些内存是空闲的, 没有办法知道。所以,
 这种场景下, 冒味的使用, 一定会导致多个进程在访问物理内存的时候,出现混乱。
所以, 内存由操作系统一管理起来, 但是又不能采用预先直接分配内存的方式, 给进程。 

原因: 因为OS也不清楚进程能使用多少内存, 使用多久。所以, 就虚拟给每一个进程分配了
4G的地址(虚拟地址)进程真正要要保存数据, 或者申请内存的时候,操作虚拟地址, 让
操作系统在给进程进行分配。这样就比较合理(同时也会节省很多空间,毕竟谁用才分配真正的
物理内存)每一个进程都无感的使用拿到的虚拟地址,背后就是OS进行了转换(页表映射)

 

进程优先级问题

1.3.11 进程优先级问题
- PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序
被CPU执行的先后顺序,此值越小进程的优先级

那NI呢?就是我们所要说的nice值了,其表示进程可被执行的优先级的修正数值这样,
当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,
则其越快被执行所以


-调整进程优先级,在Linux下,就是调整进程nice值
-nice其取值范围是-20至19,一共40个级别。
### 用top命令更改已存在进程的nice:         (root用户进行修改)
> -top
> -进入top后按“r”->输入进程PID - >输入nice值I

 按r

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值