目录
什么是进程
简单来说进程就是程序执行的过程,它代表程序在干嘛。
如图,在电脑中的任务管理器中就可查看进程,(程序是静态的,保存在磁盘中)
程序是静态的,它是保存在磁盘上的指令的有序集合,没有任何执行的概念
进程是一个动态的概念,它是程序执行的过程,包括了动态创建、调度和销毁的整个过程
进程是受操作系统调度的,一旦有进程产生,就会开辟空间
进程执行的两种方法
1.并行
假如电脑的cpu的核为8核,这个时候来了8个进程,那么每个核负责处理一个进程(你的核越多,处理的进程越多),依赖你的财力。
并发
当你的钱包只能支持你买只有一核的轻薄本时(假设),想让它处理进程速度提高,就可以用并发模式。
可以这样理解:系统把1s分为1000份,每一份执行一个进程,时间到就弹出当下进程,让进程们进行竞争(包括弹出的进程,除非进程执行完),这样就可以提高核的工作效率。
进程的内存分配
在32位的Linux系统中,每一个进程会获得4G的空间,1G的内核空间,3G的用户空间。
当然这是虚拟的空间,不然多来几个进程系统就卡死了
虚拟地址空间中的每个地址都是一个虚拟地址
虚拟地址 : 虚拟地址并不代表真实的内存空间,而是一个用于寻址的编号
物理地址 : 是指内存设备中真实存在的存储空间的编号 虚拟地址通过映射的方式建立与物理地址的关联,从而达到访问虚拟地址就可以访问到对应的物理地址
在 cpu 中有一个硬件 MMU(内存管理单元) ,负责虚拟地址与物理地址的映射管理以及虚拟地址访问 操作系统可以设置 MMU 中的映射内存段
在操作系统中使用虚拟地址空间主要是基于以下原因:
1.直接访问物理地址,会导致地址空间没有隔离,很容易导致数据被修改
2.通过虚拟地址空间可以实现每个进程空间都是独立的,操作系统会映射到不用的物理地址区间,在 访问时互不干扰.
进程执行的基础状态
进程的状态很多,这里就说几个比较重要的
运行态
运行态(TASK_RUNNING) : 此时进程或者正在运行,或者准备运行,就绪或者正在进行都属于 运行态
睡眠态
睡眠态(TASK_SLEEP): 此时进程在等待一个事件的发生或某种系统资源 可中断的睡眠(TASK_INTERRUPT) : 可以被信号唤醒或者等待事件或者资源就绪 不可中断的睡眠(可以用scanf 理解)
(TASK_UNTERRUPT) : 只能等待特定的事件或者资源就绪
僵尸态
僵尸态(TASK_ZOMBIE):进程已经结束但是还没有释放进程资源(当父进程结束时会将其销毁)
#include <stdio.h>
int main()
{
int num=-1;
printf("please input number:");
scanf("%d",&num);
printf("num=%d\n",num);
return 0;
}
TASK_RUNNING-------->TASK_INTERRUPTIBLE 等待用户输入 用户输入完成后 TASK_INTERRUPTIBLE------------->TASK_RUNNING
程序运行结束 TASK_RUNNING--------->TASK_ZOMBIE
进程的创建
在上面提到一个父进程,每个进程都需要与其它某一个进程建立父子关系,对应的进程叫做父进程。
1. Linux 系统会为每个进程分配id ,这个id作为当前进程的唯一标识,当进程结束,则会被回收。
2. 进程的id与父进程的id分别通过getpid()与getppid()来获取
通过调用fork()函数,则会产生一个新的进程。调用fork()函数的进程叫做 父进程,产生的新进程则为 子 进程。
// 创建一个子进程,并打印 Hello fork
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid = fork();
if(pid==-1)
{
perror("fork");
return -1;
}
printf("Hello fork.\n");
return 0;
}
问题1:为什么显示两次"hello fork"?
fork()函数下都属于子进程所以打印语句在两个进程中都运行了
问题2:为什么两次显示结果有差异?
如果父进程在子进程打印之前结束,则会回到终端命令后继续执行子进程;如果子进程的 打印语句在父进程结束之前执行,则会在回到终端命令前执行完毕。
通过fork()创建的子进程的特点:
1.父子进程并发执行,子进程从fork()函数之后开始执行
2.父子进程的执行顺序由操作系统决定,不是程序本身决定
3.子进程会拷贝夫进程地址空间的内容,包括缓存区,文件描述符(子进程会拷贝共享文件状态与文件偏移量等信息)
// 父子进程数据空间拷贝,缓冲区的拷贝
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
// 标准IO
write(1,"write hello.",12);
// 文件IO自带缓冲区
fputs("fputs hello.",stdout); // 注意没有换行符,stdout的缓冲区属于行
缓冲
pid_t pid = fork();
if(pid==-1)
{
perror("fork");
return -1;
}
printf("pid = %d,Hello fork.\n",getpid());
return 0;
}