1.进程是什么
进程是程序执行的过程,会去分配内存资源,cpu的调度。正在运行的程序叫进程。
并发:同一时刻可以同时完成多个任务。
-
进程: 是操作系统对正在运行的程序的抽象。进程不仅包括程序的代码,还包括程序的执行状态、内存分配、堆栈、寄存器内容等。
-
进程 ID (PID): 每个进程在系统中都有一个唯一的标识符,称为进程 ID,用于区分不同的进程。
-
父进程与子进程: 一个进程可以创建一个或多个子进程。子进程从父进程继承资源和属性,但具有自己的 PID 和独立的执行上下文。
pcb块,是一个结构体,process control block
每个进程在操作系统中都有一个进程控制块(Process Control Block, PCB),用于存储进程的状态和管理信息。PCB 包括以下内容:
-
进程 ID (PID): 唯一标识进程的编号。
-
程序计数器 (Program Counter): 当前正在执行的指令的地址。
-
寄存器状态: 包括 CPU 寄存器的内容。
-
内存管理信息: 进程的地址空间,包括代码段、数据段、堆和栈的起始地址。
-
进程状态: 进程的当前状态(运行、就绪、等待等)。
-
调度信息: 用于进程调度的相关数据,如优先级、调度策略等。
-
文件描述符表: 进程打开的文件及其状态的信息。
-
进程间通信 (IPC) 信息: 进程间通信机制的数据,如信号、消息队列等。
kernal linux内核,cpu一个一个运行
描述一个进程的所有信息
{
PID,进程标识符
当前工作路径 chdir
umask 0002
进程打开的文件列表 文件IO中有提到
信号相关设置 处理异步io,
用户id,组id
进程资源的上限-----ulimit -a,显示资源上限。
Open files 进程打开的文件上限,默认1024。可调
Statck size 栈的大小默认8m,栈一般存放(局部变量,函数参数,返回地址)
}
2.进程和程序的区别?
程序:静态
存储在硬盘中代码,数据的集合(一组指令的有序集合)
进程:动态
程序执行的过程,是动态的,包括进程的创建、调度、消亡
.c ----> a.out-----> process(pid)
1)程序是永存,进程是暂时的(有其生命周期,创建后运行,运行结束后消亡)
2)进程有程序状态的变化,程序没有
3)进程可以并发,程序无并发
4)进程与进程会存在竞争计算机的资源(进程在运行过程中需要分配和使用系统资源如cpu时间,内存空间等)
5)一个程序可以运行多次,变成多个进程
一个进程可以运行一个或多个程序
程序是进程的静态文本,而进程是程序的动态执行
内存的分布
0-3G,是进程的空间,3G-4G是内核的空间,虚拟地址
虚拟地址 * 物理内存和虚拟内存的地址 映射表 1page=4k mmu
进程的空间分配:内存图(08/19 11:30)
进程分类:
1、交互式进程
2、批处理进程 shell脚本
3、 守护进程
3.进程的作用? 并发,并行区别。
-
资源管理:进程拥有独立的地址空间和资源(如内存、文件描述符),确保各个进程之间的隔离和安全。
-
并发执行:通过创建多个进程,系统可以同时执行多个任务,提高效率和响应能力。
-
调度和管理:操作系统的调度器负责分配 CPU 时间给各个进程,优化系统性能。
-
进程间通信:进程可以通过各种机制(如管道、信号、共享内存等)交换数据和协调工作。
4.进程的状态:
3个状态,就绪→执行态→阻塞(等待,睡眠)基本操作系统
linux中的状态,运行态,睡眠态,僵尸,暂停态。
-
就绪态 (Ready):
-
定义:进程已经准备好运行,等待 CPU 时间片的分配。
-
转换到运行态:当调度器选择该进程并分配 CPU 时间片时,进程从就绪态转换到运行态。
-
-
运行态 (Running):
-
定义:进程正在 CPU 上执行。
-
转换到就绪态:当时间片用完,或者由于其他优先级更高的进程需要 CPU 时,进程会从运行态转换到就绪态。
-
转换到阻塞态:当进程等待某些事件或资源(例如 I/O 操作)时,它会从运行态转换到阻塞态。
-
转换到终止态:当进程完成执行或被终止时,它会从运行态转换到终止态。
-
-
阻塞态 (Blocked):
-
定义:进程在等待某些事件或资源(如 I/O 操作完成)。
-
转换到就绪态:当等待的事件发生,资源变得可用时,进程会从阻塞态转换到就绪态。
-
-
挂起态 (Suspended):
-
定义:进程被暂停或挂起,通常由系统管理员或操作系统主动进行。
-
转换到就绪态:当进程从挂起状态恢复时,通常会转换回就绪态,以便等待 CPU 时间片的分配。
-
转换到终止态:如果进程在挂起期间被终止,它会直接转换到终止态。
-
-
终止态 (Terminated):
-
定义:进程已完成执行,所有资源都被释放。
-
僵尸状态:在进程终止后,如果父进程尚未读取其退出状态,进程会先进入僵尸状态。
-
转换到已退出状态:父进程读取了退出状态后,进程会从僵尸状态转换到已退出状态,进程表条目最终会被清除。
-
5.进程的调度,进程上下文切换
内核主要功能之一就是完成进程调度, 硬件,bios,io,文件系统,驱动
调度算法, other,idle
rr,fifo
宏观并行
微观串行
-
进程调度:决定哪个进程在何时运行。主要策略包括:
-
时间片轮转 (Round Robin):每个进程分配固定时间片,时间片用完后调度下一个进程。
-
优先级调度 (Priority Scheduling):高优先级进程优先执行。
-
多级反馈队列 (Multilevel Feedback Queue):动态调整进程优先级,以优化系统响应和吞吐量。
-
-
上下文切换:在两个进程间切换时保存和恢复状态。步骤包括:
-
保存当前进程状态:包括寄存器值、程序计数器、堆栈指针等。
-
加载新进程状态:恢复新进程的寄存器值和其他状态信息。
-
更新调度信息:调整进程队列和状态。
-
6.查询进程相关命令
1.ps aux
查看进程相关信息
1.就绪态、运行态 R
2.睡眠态、等待态
可唤醒等待态 S
不可唤醒等待态 D
3.停止态 T
4.僵尸态 Z
5.结束态
2.top
根据CPU占用率查看进程相关信息
3.kill和killall发送一个信号
kill -2 PID
发送信号+PID对应的进程,默认接收者关闭(ctrl+c)
killall -9 进程名
发送信号 进程名对应的所有进程
强制终止进程,无法被捕获或忽略,进程不会进行清理。
用法:kill -9 PID
killall a.out
1.fork();
pid_t fork(); 叉子
一次调用,会返回两次。
-
返回值:
-
父进程: 返回新创建子进程的进程 ID (PID)。
-
子进程: 返回 0。
-
出错: 如果
fork
调用失败,返回 -1,且设置errno
以指示错误类型。 -
进程复制:
-
fork
创建一个与父进程几乎完全相同的子进程。包括进程的代码、数据、打开的文件描述符等。然而,子进程有自己独立的地址空间和 PID。
-
-
子进程先运行和是父进程先进程,顺序不确定。
变量不共享。
子进程复制父进程的0到3g空间和父进程内核中的PCB,但id号不同。
功能:通过该函数可以从当前进程中克隆一个同名新进程。
克隆的进程称为子进程,原有的进程称为 父进程。
子进程是父进程的完全拷贝。
子进程的执行过程是从fork函数之后执行。
子进程与父进程具有相同的代码逻辑。
返回值:int 类型的数字。
在父进程中:成功 返回值是子进程的pid号 >0
失败 返回-1;
在子进程中:成功 返回值 0
失败 无
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
pid_t ret = fork();
if(ret>0)
{
//father
while(1)
{
printf("发送视频\n");
sleep(1);
}
}
else if(0 == ret)
{
//child
while(1)
{
printf("接受控制\n");
sleep(1);
}
}
else
{
perror("fork error\n");
return 1;
}
return 0;
}
面试题: 一次fork生成几个进程?他们之间的关系是什么样的?
如果两次fork同时前后执行,会生成几个进程?他们之间的
关系如何表示,有多少个子进程,有没有孙进程?
2.getpid
pid_t getpid(void);
功能:
获得调用该函数进程的pid
返回值
-
返回当前进程的进程 ID(
pid_t
类型),如果调用成功。 -
在错误情况下(通常不会发生),返回
-1
,并设置errno
来指示错误类型,但getpid
函数通常不会失败。
主要用途
-
获取当前进程的 PID:可以用来识别和管理当前进程。
-
进程间通信:进程可以使用其 PID 与其他进程通信或管理资源。
-
调试和日志:获取进程 PID 以便于在调试和日志记录中跟踪进程的行为。
3.getppid
pid_t getppid(void);
功能:
获得调用该函数进程的父进程pid号
返回值:
返回父进程id号
fork函数之后的数据处理互不影响,getpid,getppid函数使用
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
int a = 20;
int main(int argc, char *argv[])
{
pid_t ret = fork();
if(ret>0)
{
//father
sleep(3);
printf("father is %d pid %d ,ppid:%d \n",a,getpid(),getppid());
}
else if(0 == ret)
{
//child
printf("child a is %d\n",a);
a+=10;
printf("child a is %d pid:%d ppid:%d\n",a,getpid(),getppid());
}
else
{
perror("fork error\n");
return 1;
}
printf("a is %d pid:%d\n",a,getpid());
return 0;
}
fork()&&fork()||fork();
应用场合:
1)一个进程希望复制自己,使父子进程同时执行同的代码段。网络服务中会比较多见。
2)一个进程需要执行一个不同的程序。fork+exec