C++程序员必会的知识储备
程序与进程
程序:
程序是指编译好的二进制文件,存储在磁盘上,不占用系统资源(CPU、内存、设备等),程序中包含了一系列信息,这些信息描述了如何在运行时创建以进程。--不妨将程序看作一个数据集合
- 二进制格式标识:每一程序文件都包含用于描述可执行文件格式的元信息。内核利用此信息来解释文件中的其它信息。(Linux中使用ELF格式连接格式)
- 机器语言指令:对程序算法进行编码
- 程序入口地址:标识程序开始执行时的起始指令的位置。
- 数据: 程序文件包括的变量初始值和程序使用的字面量(常数)
- 符号表及重定位表:描述程序中函数和变量的位置和名称。这些表格有多重作用,其中包括调试和运行时的符号解析。
- 共享库和动态链接信息:程序文件所包含的一些字段,列出程序运行时需要使用的共享库,以及加载共享库的动态链接器的路径。
- 其它信息
进程:
进程是正在运行的程序实例,是一个抽象的概念。占用系统资源,在内存中执行。是一个具有一定独立功能的程序关于某个数据集合的活动。它是操作系统动态执行的基本单位,在传统的操作系统中,进程既是资源的基本分配单位,也是执行的基本单位。
可以用一个程序来创建多个进程,进程是由内核定义的抽象实体,并未该实体分配用来执行程序的各项系统资源。从内核的角度看,进程由用户内存和一系列内核数据结构组成,其中用户区空间包含了程序代码以及所使用的变量,而内核区数据结构则用于维护进程的状态信息(主要通过PCB进程控制块维护)。
并发与并行
并发:
我们所说的并发是站在单个cpu的角度而言的。在一台计算机中,通常有多个cpu(可以打开自己的任务管理器查看,现在一般是8个核的),但是同一个cpu永远不可能正真的同时运行多个任务。比如,以及淘汰了的单道程序设计,所有的进程都一个一个排队执行。若A阻塞(发生等待时事件),B只能等待,即使cpu处于空闲状态,极大的浪费了系统资源(我们总是追求让cpu不停歇的工作,已充分利用cpu),我们在人机交互的时候,不可避免地回发生阻塞事件,如等待输入。
所以,我们提出了并发地概念(再次强调:并发是对于单个cpu而言的)
并发是指在操作系统中,一个时间段中有多个进程都处于已启动运行到运行完毕之间的状态。但是,任何一个时刻点仍只有一个进程在运行。例如:我们可以一边听歌、一边写博客。
由并发引出的是多道程序设计,它是指在内存中同时存放几道相互独立的程序,它们在管理程序控制下,相互穿插运行。多道程序设计必须依靠硬件支持(时钟中断)。
时钟中断:并发时,任意进程执行期间都不希望放弃cpu(每一进程都想独占cpu),如果随cpu的期望,那不就成了单道程序设计了,显然这样是不好的。因此,系统需要一种强制的机制让进程让出cpu资源的手段。时钟中断是以硬件作为基础实现的,对进程而言具有不可抗拒力(降维打击)。中断是由中断程序根据调度算法来完成调度的执行。
在多道程序设计中,多个进程轮流使用cpu(分时复用cpu)。而当下常见的cpu为纳米级,1秒可以执行大约10亿条指令。人眼的反应速度是毫秒级,所以在人看来是同时运行的。实质上:宏观上并行,微观上串行。
并行:
在某个时间点上同时有多个经常在执行,这是对于多个cpu而言的。每个cpu处理一个进程,多个cpu可以同时处理多个进程。(流水线技术)
进程控制块PCB
在内核中有一个进程控制块,维护了关于进程相关的信息。我们作为程序员来说要清晰的了解PCB。在Linux中进程控制块是tack_struct结构体。 /usr/src/linux-headers...
PCB中主要维护的信息:(也就是task_struct结构体中的字段)
- 进程ID。系统中每一个进程都有唯一的进程ID,其实就是个非负整数 pid_t
- 进程的状态。就绪、运行、挂起、停止等
- 进程切换时需要保存和恢复的一些cp寄存器。(现场信息)
- 描述虚拟地址空间的信息
- 控制终端的信息
- 当前进程的工作目录
- umask掩码
- 文件描述符表
- 信号相关的信息
- 用户id和组ID
- 会话和进程组
- 经常可以使用的资源上限(ulimit -a)
进程的状态
详细可以分为:初始化、就绪、运行、等待(阻塞)、终止
查看进程:ps aux / auj
实时显示进程动态:top
进程号和进程组相关函数
每一个进程都由进程号来唯一标识,其类型为pid_t(无符号整型),其范围0~32767
进程号总是唯一的,但是可以重复使用。当一个进程终止后,该进程称为杯创建进程的父进程。对应进程号称为父进程号(PPID)
进程组是一个或多个进程的集合。它们直接可以相互联系,进程组可以结束统一终端的各种信号,关联的进程有一个进程组号(PGID)。默认情况下,第一个进程的ID作为PGID.
相关函数:
pid_t getpid(void); //获取当前进程
pid_t getppid(void); //获取父进程id
pid_t getpgid(pid_t pid); //获取某一个进程的组ID
uid_t getuid(void); //获取当前进程的用户
git_t getgid(void); //获取当前进程使用的用户组ID
uid_t geteuid(void); //有效用户
git_t getegid(void); //有效用户组