一、进程的概念
1.进程
进程是系统进行资源分配和调度的一个独立单元,它是操作系统结构的基础。进程是程序的一次执行过程,包含了程序代码、当前活动、系统资源(如CPU、内存、文件等)的使用情况等信息。每个进程都有自己独立的内存空间和系统资源。
2.pcb
pcb
是 Process Control Block
(进程控制块)的缩写,即进程控制块,是操作系统中用于存储进程管理所需信息的数据结构。它记录了操作系统的进程管理所需要的所有信息,包括:
- PID(进程标识符):唯一标识一个进程。
- 当前工作路径:进程当前的工作目录,通过
chdir
等系统调用可以改变。 - umask:文件创建掩码,影响新创建文件的权限。例如,
umask 0002
意味着新创建的文件默认不允许组用户和其他用户写入。 - 打开的文件列表:进程打开的所有文件及其相关信息,如文件描述符、文件模式等。
- 信号相关设置:处理异步事件,如中断、错误等。进程可以定义对不同信号的处理方式(忽略、捕捉或默认处理)。
- 用户ID和组ID:执行该进程的用户和组的身份标识。
- 进程资源的上限:系统为该进程分配的资源上限,如最大打开文件数、最大内存使用量等。可以通过
ulimit -a
命令查看或设置这些限制。
3.进程和程序的区别
- 静态与动态:
- 程序:是静态的,它是一组指令和数据的集合,存储在非易失性存储介质(如硬盘)上。程序本身不执行任何操作,它只是等待被执行。
- 进程:是动态的,它是程序在计算机上的一次执行过程。它包含了程序代码、数据以及系统分配给该程序的各种资源(如内存空间、文件描述符等)。进程是系统进行资源分配和调度的一个独立单元。
- 存在性与生命周期:
- 程序:是永存的,只要存储介质没有损坏,程序就可以一直存在。
- 进程:是暂时的,有生命周期,包括创建、运行、等待、挂起、终止等状态。一旦进程执行完毕或被系统终止,它就不再存在。
- 状态变化:
- 程序:没有状态变化,它只是静态的代码和数据集合。
- 进程:有状态变化,如运行状态、就绪状态、阻塞状态等。进程的状态会随着执行过程中的事件(如I/O操作、时间片结束等)而发生变化。
- 并发性:
- 程序:没有并发性,它只是一个代码和数据的集合,不会自己执行。
- 进程:具有并发性,系统中可以同时运行多个进程,这些进程之间可能并发执行,也可能并行执行(在多处理器或多核处理器上)。
- 资源竞争:
- 程序:不直接涉及资源竞争,因为它不直接执行。
- 进程:进程之间会存在资源竞争,因为它们可能同时需要访问CPU、内存、I/O设备等资源。操作系统通过调度算法来管理这些资源,确保进程的公平性和高效性。
- 与程序的关系:
- 一个程序可以多次运行,每次运行都会创建一个新的进程。因此,一个程序可以对应多个进程。
- 一个进程可以执行一个或多个程序,特别是在现代操作系统中,一个进程可以加载并执行多个模块或库。
- 内存分布:
- 在许多操作系统中(如Linux),进程的地址空间被划分为用户空间和内核空间。用户空间通常位于低地址区域(如0-3G),用于存储进程的代码、数据等;内核空间位于高地址区域(如3G-4G),用于存储操作系统代码和数据,以及实现进程调度、内存管理等核心功能。这种划分是虚拟的,通过内存管理单元(MMU)和页表实现物理内存和虚拟内存之间的映射。
4.进程的分类
进程分类: 1、交互式进程
2、批处理进程 shell脚本
3、 守护进程
*5.进程的状态:
3个状态,就绪→执行态→阻塞(等待,睡眠)基本操作系统
linux中的状态,运行态,睡眠态,僵尸,暂停态。
6.进程的作用
- 资源封装:进程封装了运行程序所需的资源,使得操作系统能够方便地对这些资源进行管理和调度。
- 执行程序:进程是程序执行的载体,操作系统通过创建进程来执行程序,实现程序的动态运行。
- 实现并发:操作系统通过创建多个进程,可以在同一时间段内执行多个任务,从而提高系统的整体效率和吞吐量。
- 系统安全:通过进程隔离,操作系统可以防止不同进程之间的相互干扰,保证系统的安全性和稳定性。
7.并发与并行的区别
- 定义:
- 并发:指两个或多个事件在同一时间间隔内发生,但这些事件并不是同时发生的。在操作系统中,并发通常指的是多个进程或线程在宏观上同时运行,但在微观上(即CPU的指令执行层面)是交替执行的。
- 并行:指两个或多个事件在同一时刻同时发生。在并行计算中,多个任务可以同时被执行,因为它们被分配到不同的处理器或处理单元上。
- 资源需求:
- 并发通常不需要额外的硬件资源,它主要通过时间片轮转、上下文切换等机制来实现多个任务的交替执行。
- 并行则需要额外的硬件资源来支持,如多核处理器、分布式计算环境等,以便能够同时执行多个任务。
- 效率与速度:
- 并发虽然可以在宏观上提高系统的整体效率,但在单个任务的执行速度上并没有明显的提升。
- 并行则能够显著提高单个任务的执行速度,因为它允许多个任务同时执行,从而减少了总体执行时间。
while (1) {
发视频
}
while (1) {
上下左右
}
- 如果这两个任务在同一台计算机上执行,并且只有一个CPU核心可用,那么它们将通过并发的方式执行,即操作系统通过时间片轮转等方式使这两个任务交替执行。
- 如果这台计算机有多个CPU核心,且这两个任务被分配到不同的CPU核心上执行,那么它们将并行执行,即同时执行。
需要注意的是,并发和并行是操作系统和硬件层面的概念,而上述代码示例并没有直接体现这些概念。在实际应用中,要实现并发或并行,通常需要使用多线程或多进程等编程技术
进程的调度
进程调度是操作系统内核的主要功能之一,它决定了哪个进程可以获得CPU资源并运行。进程调度的目标是公平、高效地分配CPU资源,以满足进程的运行需求。以下是进程调度的几个关键点:
- 调度算法:
- 轮转调度(Round-Robin, RR):将CPU时间分成若干个时间片,每个进程在一个时间片内执行,时间片结束后切换到下一个进程。这种算法可以提高CPU的利用率,但可能会导致上下文切换开销增加。
- 先进先出(First-In, First-Out, FIFO):也称为先来先服务(FCFS),按照进程到达系统的先后顺序进行调度,先到达的进程先执行。这种算法简单直观,但可能会导致长作业等待时间过长。
- 优先级调度:根据进程的优先级进行调度,优先级高的进程先执行。这种算法可以根据进程的重要性进行调度,但可能会导致低优先级进程饿死。
- 短作业优先(Shortest Job First, SJF):选择执行时间最短的进程。这种算法可以提高系统的整体效率,但同样可能导致长作业饥饿。
- 其他算法:如多级反馈队列调度、多级队列调度等,这些算法结合了上述算法的某些特点,以更好地适应不同的应用场景。
- 调度时机:
- 进程创建时:当新进程被创建时,需要被加入到调度队列中等待CPU资源。
- 进程终止时:当进程执行完毕或异常终止时,需要释放其占用的CPU资源,并重新调度其他进程。
- 进程阻塞时:当进程因等待某个事件(如I/O操作完成)而阻塞时,需要将其从CPU上撤下,并调度其他进程执行。
- 进程唤醒时:当被阻塞的进程因等待的事件完成而被唤醒时,需要将其重新加入到调度队列中等待CPU资源。
- 调度过程:
- 收集系统信息:操作系统需要收集有关系统中所有进程的信息,如进程的状态、优先级、需要的资源等。
- 选择进程:根据调度算法和调度策略选择下一个要执行的进程。
- 分配CPU:将选中的进程分配到CPU上,并将其状态设置为运行状态。
- 执行进程:进程在CPU上执行其指令和数据。
- 回收CPU:当进程执行完毕或需要被替换时,回收其占用的CPU资源。
进程上下文切换
进程上下文切换是操作系统内核在CPU上对于进程(包括线程)进行的一种活动,主要目的是在多个进程之间共享CPU资源。以下是进程上下文切换的几个关键点:
- 概念:
- 上下文切换可以认为是内核在CPU上对于进程进行的活动,包括挂起一个进程、存储其上下文信息、检索下一个进程的上下文信息、恢复其在CPU上的执行状态,并跳转到程序计数器所指向的位置以继续执行。
- 发生时机:
- 中断发生时:当发生中断(如硬件中断、软件中断)时,CPU会暂停当前执行的进程,并保存其上下文信息,然后跳转到中断处理程序执行。当中断处理完成后,CPU会恢复之前被挂起的进程的上下文信息,并继续执行。
- 进程调度时:当需要进行进程调度时(如时间片用完、进程阻塞/唤醒等),操作系统内核会保存当前执行进程的上下文信息,并检索下一个要执行的进程的上下文信息,然后恢复其在CPU上的执行状态。
- 上下文信息:
- 上下文信息是指进程在被调度执行前的状态信息,包括程序计数器(PC)、栈指针、寄存器的值等。这些信息用于恢复进程的执行状态,以便进程可以从上次暂停的地方继续执行。上下文信息通常存储在PCB(进程控制块)中,以便操作系统可以快速获取和更新这些信息。
- 性能影响:
- 上下文切换是操作系统内核中的一项重要活动,但它也会带来一定的性能开销。频繁的上下文切换会增加CPU的负载和延迟,降低系统的整体性能。因此,在设计操作系统和应用程序时,需要合理控制上下文切换的频率和开销。
内核的其他主要功能
除了进程调度和进程上下文切换外,操作系统的内核还负责以下主要功能:
- 硬件管理:管理计算机的硬件资源,如CPU、内存、I/O设备等。
- BIOS接口:提供与BIOS(基本输入输出系统)的接口,以便操作系统能够访问计算机的底层硬件。
- I/O管理:处理输入/输出操作,包括与外设的通信和数据传输。
- 文件系统:管理磁盘上的文件和目录结构,提供文件的创建、读取、写入、删除等操作。
- 驱动管理:管理各种设备驱动程序,
二、查询进程相关命令
*1.ps aux
查看进程相关信息
1.就绪态、运行态 R
2.睡眠态、等待态
可唤醒等待态 S
不可唤醒等待态 D
3.停止态 T
4.僵尸态 Z
5.结束态
2.top
根据CPU占用率查看进程相关信息
3.kill和killall发送一个信号
kill -2 PID 15
发送信号+PID对应的进程,默认接收者关闭
killall -9 进程名
发送信号 进程名对应的所有进程
killall a.out
*4.fork();
pid_t fork(); (叉子)
一次调用,会返回两次。不需要传参数
子进程先运行和是父进程先进程,顺序不确定。
变量不共享。
子进程复制父进程的0到3g空间和父进程内核中的PCB,但id号不同。
功能:通过该函数可以从当前进程中克隆一个同名新进程。
克隆的进程称为子进程,原有的进程称为 父进程。
子进程是父进程的完全拷贝。
子进程的执行过程是从fork函数之后执行。
子进程与父进程具有相同的代码逻辑。
返回值:int 类型的数字。
在父进程中:成功 返回值是子进程的pid号 >0
失败 返回-1;
在子进程中:成功 返回值 0
失败 无
练习:让2个while同时进行
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main(int argc, const char *argv[])
{
pid_t ret=fork();
if(ret>0)
{
while(1)
{
printf("aaa\n");
sleep(1);
}
}
else if(ret==0)
{
while(1)
{
printf("ccc\n");
sleep(1);
}
}
else
{
perror("fork error\n");
return 1;
}
return 0;
}
运行结果会出现 aaa aaa 是因为:进程是随机的。
5.getpid
pid_t getpid(void);
功能:
获得调用该函数进程的pid
参数:
缺省
返回值:
进程的pid
6.getppid
pid_t getppid(void);
功能:
获得调用该函数进程的父进程pid号
参数:
缺省
返回值:
返回父进程id号
练习:
fork()&&fork()||fork()
几个进程? 五个 看最后一层有多少个进程
分析:fork()它返回值有两种情况,大于0,等于0,&&如果左边为1,右边执行,如果为0,右边不执行,|| 如果左边为1,右边不执行,如果左边为0,右边执行,按照这个思想去分析。
练习:动态生成n个子进程,并打印输出各自进程的pid号。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int n =5;
int i = 0 ;
for(i=0;i<n;i++)
{
pid_t pid = fork();
if(pid>0)
{
}
else if(0 == pid)
{
printf("child pid:%d\n",getpid());
exit(0);
}
else
{
perror("fork");
return 1;
}
}
return 0;
}