进程(Process)
一、概念
进程是操作系统资源分配的最小单元(文本段、数据段、系统数据段)
进程:就是程序执行的过程,包括创建、调度和消亡,是活的
程序:一段数据的集合,是死的
二、常用命令
三、进程的创建
1、进程的内存空间
电脑会在硬件层为每个进程准备真实的内存空间
在32位操作系统(有32根地址线)中,会为运行过程中的进程开辟0 - 4G虚拟内存空间
在64位操作系统(有64根地址线)中,会为运行过程中的进程开辟0 - 8G虚拟内存空间
文本段
存储代码和指令
数据段
存储全局变量、静态变量、字符串常量,未经初始化变量值为0值
在编译时分配空间,程序运行时,将a.out数据段加载到内存数据段中
程序结束回收数据段空间
系统数据段
栈区:操作系统管理区域、存放局部变量、执行到变量定义时分配空间,超过变量 作用域回收变量空间,未经初始化为随机值
堆区:程序员管理的区域,malloc申请、free释放
内核
操作系统核心区域,用户无法访问,负责内存管理、CPU管理、硬件设备管理、进程管理、文件系统管理
2、多个进程的存储
1. 进程的空间是独立的
2. 单核:一个CPU在同一时刻只能执行一个任务
3. 宏观并行,微观串行
4. 物理地址空间是独立的,虚拟地址空间共用同一份,所以多个进程并不是虚拟机地址空间相加
四、进程的调度
1、宏观并行,围观串行
多个进程在执行时总的看上去似乎是一起执行的,但实际是因为电脑依次处理每个进程时的速度较快导致的该现象,
例如:父子两个进程并不是同时执行的,是有先后顺序的,谁先谁后不清楚
PCB(Process Control Block,进程控制块)
操作系统内核管理进程的核心工具,它为进程的创建、执行、切换和终止提供了必要的信息和控制机制
MMU(Memory Management Unit,内存管理单元)
计算机硬件中的一个重要组件,主要负责管理内存访问和虚拟内存与物理内存之间的地址转换
2、进程的状态
3、CPU调度任务规则
一个任务执行完毕后,如何选择下一个执行的任务?
常见进程调度算法:
a. 先来先执行,后来后执行
b. 高优先级调度算法
c. 时间片轮转调度算法
时间片:CPU在某个进程任务中执行的一段时间
d. 多级队列反馈
e. 负载均衡调度算法
4、进程相关的函数接口
man 2 fork
pid_t fork(void);
功能:
创建一个子进程
参数:
缺省
返回值:
成功在父进程中返回创建的子进程的PID
在子进程中返回0
失败返回-1
注意:
1、子进程是父进程的不完全副本,会复制父进程的数据区、BSS区、堆区、栈区、参数和环境变量( 例一、例二),除了以上外还会复制输入输出缓冲区(例三)。2、父进程结束,就会变成孤儿进程,孤儿进程会被1号进程(init)收养(例二)
例一 :
int mian(void)
{
pid_t pid;
pid = fork();
if (-1 == pid)
{
ERR_MSG("fail to fork");
return -1;
}
if (0 == pid)
{
printf("子进程(PID:%d)执行!\n", getpid());
}
else if (pid > 0)
{
printf("父进程(PID:%d)执行!\n", getpid());
}
printf("都会执行!\n");
return 0;
}
过程:结果:
例二: 创建一个父进程的2个子进程,要求子进程中打印自己的PID及父进程的PID,
父进程中打印自己的PID及两个子进程的PID
父进程先结束,子进程成为孤儿进程
pid_t pid;
pid_t pid1;
pid = fork();
if (-1 == pid)
{
ERR_MSG("fail to fork");
return -1;
}
if (0 == pid)
{
printf("子进程1 PID:%d PPID:%d\n", getpid(), getppid());
}
else if (pid > 0)
{
pid1 = fork();
if (-1 == pid1)
{
ERR_MSG("fail to fork");
return -1;
}
if (0 == pid1)
{
printf("子进程2 PID:%d PPID:%d\n", getpid(), getppid());
}
else if (pid1 > 0)
{
printf("父进程 PID:%d 子进程PID:%d %d\n", getpid(), pid, pid1);
}
}
子进程先结束,父进程不结束
pid_t pid;
pid_t pid1;
pid = fork();
if (-1 == pid)
{
ERR_MSG("fail to fork");
return -1;
}
if (0 == pid)
{
printf("子进程1 PID:%d PPID:%d\n", getpid(), getppid());
}
else if (pid > 0)
{
pid1 = fork();
if (-1 == pid1)
{
ERR_MSG("fail to fork");
return -1;
}
if (0 == pid1)
{
printf("子进程2 PID:%d PPID:%d\n", getpid(), getppid());
}
else if (pid1 > 0)
{
printf("父进程 PID:%d 子进程PID:%d %d\n", getpid(), pid, pid1);
}
}
while (1)
{
}