目录
谢谢帅气美丽且优秀的你看完我的文章还要点赞、收藏加关注
没错,说的就是你,不用再怀疑!!!
希望我的文章内容能对你有帮助,一起努力吧!!!
1、进程
程序:数据结构+算法
数据结构:用来表示人们思维对象的抽象概念的物理表现叫做:数据。对于数据进行处理操作规则叫 做:指令操作
对某一有限数据集所实施的、目的在与借鉴某一问题的一组有限的指令集合,称为:计算。
计算机就是用指令来处理数据。程序就是数据和指令的集合,一个程序的执行过程就是计算。
1.1程序的执行方式
- 顺序方式
- 一个程序完全执行完毕之后才能执行下一个程序
- 比如:一个程序分为三步骤
- 输入数据--->计算-->打印结构
- 缺陷:
- CPU的利用率非常低
- 并发执行
- 把一个取指令的执行过程,分为几个不同步骤
- 不同步骤由不同的硬件完成,这样可以多个程序同时执行
为了提供CPU的利用率,增加 吞吐量 并发执行 ,现代操作系统特地引入 进程 概念
1.2进程是个什么东西
进程是具有独立功能的程序,关于某个数据集合上的依次运行活动。
1.3进程和程序区别
1. 程序是静态的概念(是指令的有序集合 ,“程序文件”),进程是一个动态概念(动态产生,动态消 亡)
2. 进程是一个程序的一次执行活动,一个程序可以对应多个进程。
3. 进程是一个独立的活动单位,进程的是竞争系统资源的基本单位。
进程和程序的区别,好比 “ 炒菜和菜谱 ” 的区别
2、OS为什么要引入进程
就是为了能够让程序并发执行(同一时间段有多个程序在运行);进程是如何做到让多个程序并发执行 呢?
程序的并发,实际就是进程的并发。进程如何同时运行,如何并发?
2.1进程状态
OS把一个进程的执行过程,分为了几个不同的阶段(状态)
- 创建态:在进程创建的时候,系统会生成一个空白的PCB(proccess control block)进程控制块
- 就绪态 (Ready):准备工作已经做好了,只要有CPU就可以了。就可以执行了。
- 运行态 (Running):CPU正在执行这个进程的指令的。
- 阻塞态 (Blocking,等待waiting):进程正在等待其他的外部事件。
- 消亡态:会释放,PCB(proccess control block)进程控制块
PCB(proccess control block)进程控制块
进程可以在这些状态下进行切换。
“ 就绪队列 ”:Ready Queue
- 所处 “ Ready ” 状态的进程,都在一个 “ 后备队列 ”,“ 调度程序 ” 负责确定下一个进入 “ Running ” 状态的进程。
“ 调度策略 ”:调度算法
- 分时系统:调度策略以 “ 时间片轮转 ” 为主要策略的系统。
- “ 时间片轮转 ” :分时,每一个进程执行一段时间(“ 时间片 ”)
- 如:大部分的桌面系统都是分时系统: linux,android,windows,macos,unix ...
- 实时系统:调度策略以“ 实时策略 ” 为主要策略的系统
- “ 实时策略 ”:每次调度都取优先级最高的那个进程执行,直到这个进程执行完毕或者它主动 放弃CPU再或者其他更高的优先级的进程进行抢占。
- 如: ucos,freeRTOS...
- 抢占:插队,“ 强盗逻辑 ”
3、程序执行过程
程序的执行过程:进程的动态生成
执行过程:分配资源----->产生进程---->执行指令...
进程要做的第一件事:就是申请一块内存区域来存储程序的数据,不同的数据属性是不一样,分区域来 存储程序数据的。
3.1Linux的进程地址空间的分布
“ 分段 ”:分不同的逻辑区域
Linux对与进程的数据进行分段管理,不同的属性的数据,存储在不同的“ 内存段 ”中,不同的内存段 (内存区域)的属性和管理方法都是不一样。
- .txt :文本区
- 主要存放代码
- 只读并且共享的,这段内存在程序运行期间(进程存活期间),不会被释放。
- “代码段”随程序的持续性(随进程的持续性)
- .data :数据段
- 主要存放程序的已经初始化的全局变量和已经初始化的 static (静态)变量。
- 可读可写,这段内存在进程运行期间,会一直存在,随进程持续性。
- .bss :数据段
- 主要存放程序中没有初始化的全局变量和没有初始化的static变量。
- 可读可写,这段内存在进程运行期间,会一直存在,随进程持续性。
- .bss 段,在进程初始化的时候,(可能)会全部初始化为0.
- .rodata : read only data 只读数据段
- 主要存放程序中的只读数据(如:字符串常量,整型常量....)。
- 只读,这段内存在进程运行期间,会一直存在,随进程持续性。
- stack :栈空间(栈区)
- 主要存放局部变量(非static变量)
- 可读可写,这段空间,会自动释放(代码块执行完毕,代码块中的局部变量的空间就释放了) 随代码块持续性。
- 返回一个局部变量的地址,是有问题的原因就是在于这里。
- heap :堆空间(堆区)动态内存区域
- 主要是 malloc/realloc/calloc 等动态分配的空间。
- 可读可写的,这段内存在进程运行期间,一旦分配,就会一直存在,直到手动释放,或者进程 消亡,
- 防止 “内存泄漏” / “ 垃圾内存 ” 一定要主要一旦开辟空间,就要收到释放。
使用的内存地址:并不是物理地址,而是虚拟地址(虚拟内存)。
- 用户内存 (用户态)
- 内核内存 (内核态)
- 如:是 4G 内存,其中有一个 1G 是内核内存
4、Linux下的进程相关的API函数
4.1创建一个新的进程
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
int main()
{
// 父进程创建子进程
pid_t id = fork();
if(id == 0)// 子进程,那么将该子进程需要执行的代码写道该if下面就可以了
{
for(int i = 0;i < 10;i++)
std::cout << getpid() << ":" << i << std::endl;
}
id = fork();
if(id == 0)// 子进程,那么将该子进程需要执行的代码写道该if下面就可以了
{
for(int i = 10;i < 20;i++)
std::cout << getpid() << ":" << i << std::endl;
}
std::cout << "123456" << std::endl;
while(1);
return 0;
}
4.2获取进程id号
获取当前进程 id 号
获取父进程 id 号
4.3进程的退出
进程的退出存在两种情况:
- 自杀(自己退出)
- main 函数的返回,进程就会退出
- 调用进程退出函数
他杀(被操作系统干掉/其他进程干掉)
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
int main()
{
pid_t pid = fork();
if(pid == 0)
{
for(int i = 0;i < 10;i++)
{
if(i == 5)
_exit(0);
std::cout << i ;
}
std::cout << "儿" << std::endl;
}
else
{
for(int i = 0;i < 10;i++)
{
if(i == 5)
exit(0);
std::cout << "父:" << i ;
}
std::cout << std::endl;
}
return 0;
}
4.4等待子进程的结束
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
pid_t pid = fork();
if(pid == 0)
{
sleep(1);
for(int i = 0;i < 1000;i++)
std::cout << i << std::endl;
return 0;
}
else
{
int status = 0;
int s_pid = waitpid(-1,&status,0); // 0非阻塞
std::cout <<"id:" << s_pid << "退出码:" <<status << std::endl;
if(status == 0)
{
std::cout << "程序正常退出" << std::endl;
}
else if(status == -1)
{
std::cout << "程序因为xxx异常退出" << std::endl;
// 弹出程序程序的按钮供用户选择/自动重启程序
}
}
return 0;
}