进程/线程?并发/并行?
1.引子
下面这张图片非常生动形象地描述了进程与线程和它们之间的关系。

2.进程
2.1.什么是进程
系统分配资源的基本单位。
进程是程序运行所需的完整环境,是一个活动的实体,不仅包含程序代码,还包含以下内容:
- 堆栈(Stack):用于存储函数参数、局部变量等临时数据
- 数据段(Data Section):用于存储全局变量
- 堆(Heap):运行时动态分配的内存区域
ps:甚至可以包含文件列表、输入输出设备等。
2.2.进程控制块(Process Control Block)
进程控制块(PCB)是操作系统中用于描述进程状态和属性的数据结构。它包含以下信息:
- 进程状态
- 程序计数器(PC)
- CPU寄存器状态
- 内存管理信息
- 调度信息
2.3.进程状态
进程在其生命周期中会经历多个状态转换:

- 新建(New):进程刚被创建
- 就绪(Ready):等待 CPU 调度执行
- 运行(Running):正在执行
- 等待(Waiting):等待 I/O 或其他事件完成
- 终止(Terminated):执行完成或被强制终止
下面是更为详细的七态图:

- 挂起(静止)就绪:进程具备运行条件但目前在二级存储器中,只有当它被调换到主存才能被调度执行。
- 挂起(静止)等待:进程正在等待某一个事件且在二级存储器中。
2.4.进程类型
-
独立进程
不与其它进程共享数据或相互影响的进程
-
协作进程
需要与其它进程共享数据或协同工作的进程
但是进程之间是本来是相互独立的,那么协作进程是怎么进行的,这就涉及了------进程通信(IPC)。
2.5.进程通信
内存共享
顾名思义,就是多个进程共享一个内存空间。
一个进程将数据写入共享的内存空间,另一个进程从中读取,实现通信。
ps: 开辟这块共享的内存空间是需要系统调用的,但接下来操作内存无需系统调用。
消息传递
类似"邮箱"(端口),可以设立消息缓冲区,处于操作系统空间,需要提供系统调用 ( send(), receive() ) 来发送和接收信息。
在这种模式下,进程通过操作系统传递消息进行通信:
-
直接通信 :进程直接指定发送或接收方
例如:send(B, message) 表示 A 向 B 发送消息
-
间接通信 :通过邮箱(mailbox)传递消息
例如:send(X, message) 表示发送到邮箱 X
-
同步机制:发送或接收时可选择阻塞或非阻塞模式
-
缓冲机制:消息可暂存于队列中,队列容量可为 0(无缓冲)、有限或无限
管道、套接字和远程过程调用等都是属于消息传递。
监听端口:保持开放,接收所有进程的消息。
3.线程
3.1.什么是线程
CPU调度和执行的基本单位。
线程本身不包含代码,通过程序计数器 指向特定代码段(打破一个进程拥有单一PC的限制),同时每个线程拥有自己的栈空间,从而可以并发处理特定代码段。
一个进程可以有多个线程,而且同一进程中的线程共享资源,调度所需的成本远小于进程。
3.2.线程的实现方式
- 内核级线程(Kernel-level Thread):由操作系统直接管理,调度开销大,但支持真正的并发。
- 用户级线程(User-level Thread):由线程库在用户空间管理,创建和切换快,但无法利用多核CPU。
- 混合线程(Hybrid Thread):结合上述两种方式,如 Java 的线程模型就是基于操作系统线程实现的。
4.并发与并行
并发 :通过快速切换上下文 (或者是CPU调度),以达到同一时刻处理多个任务的"假象";
并行:真正同时执行多个任务(通过多核CPU)。
上下文:就是进程所处环境的状态,包括PC、CPU寄存器的数据、主存的内容。
中断触发时,CPU硬件会自动做:1.切换到内核栈;
2.把PC等数据压入栈;
3.跳转到中断处理程序。
数据并行
数据分配到多个核心,同时执行相同操作。
比如,在对一个数组判断其中质数的个数时,将数组分为多组,同时进行判断计数。
任务并行
数据可以相同,也可以不同,同时执行不同操作。
比如,对一个数组同时执行max, min, avg操作;
也可以是对两个数组,一个执行max,另一个执行min。