Linux软件编程(四)多任务与多进程管理
一、什么是多任务(并发)
多任务指系统能够同时处理多个任务的能力。实现方式主要有:
多进程
多线程
进程间通信(IPC)
二、进程的基本概念
定义:正在运行的程序,是程序在内存中执行的过程,会消耗 CPU 和内存。
gcc main.c ----编译---> a.out ----运行---> ./a.out 应用程序(硬盘) 可执行文件(硬盘) 进程(内存+CPU参与)
程序 vs 进程:
程序:静态的数据集合,存储在硬盘空间
程序运行起来可以产生进程;
一个程序可以产生多个进程进程:是一个程序动态执行的过程,需要消耗内存和CPU,
进程具备动态生命周期,从产生到调度再到消亡
一个进程中也可执行多个程序
三、进程的内存布局
进程创建时,操作系统为其分配 0~4G 的虚拟内存空间,典型分区如下:
内核区
文件管理、进程管理、内存管理等
栈区(Stack)
保存函数调用关系(保护/恢复现场)
存储局部变量、函数的形参、函数的返回值
堆区(Heap)
由开发人员动态内存分配(
malloc
/free
),需手动释放
数据区(Data Segment)
字符串常量区:存储字符串常量
BSS 段:未初始化的全局变量、未初始化的静态变量(static)
-->bss段初始时按位清0Data 段:1. 已初始化的全局变量 2. 已初始化的静态变量
文本区(Text Segment)
存放指令代码和,常量(例如a, 10, oxAA等)
四、进程调度
CPU 执行特性:数据处理速度快;
宏观并行、微观串行(一次只执行一个进程的指令)
常见调度算法:
时间片轮询:每个进程按时间片(如 10ms)轮流执行
先来先服务(FCFS):按到达顺序执行
短作业优先:耗时短的优先执行
优先级调度:高优先级先执行
五、进程状态
操作系统进程三态图:
Linux操作系统的进程状态:
运行态(用户运行态、内核运行态) R
正在执行,且被CPU任务调度所执行的进程
就绪态 R
正在执行,没有CPU任务调度执行的进程(只缺少cpu)
可唤醒等待态 S
也称为睡眠态,阻塞等待资源的进程
不可唤醒等待态 D
不想被CPU任务调度所打断的进程任务可以设置为不可唤醒等待态
暂停态 T
被暂停执行的进程
僵尸态 Z
进程执行结束,空间没有被回收(子进程运行完,此时父进程还没运行完)
结束态 X
进程执行结束,空间被回收
六、进程的消亡
进程退出
return
(在 main 中)exit(status)
(C 库函数)_exit(status)
(系统调用,直接退出)status=0
表示正常退出,非 0 表示异常退出
资源回收
wait()
/waitpid()
回收子进程资源,防止僵尸进程让进程成为孤儿进程,由系统回收(典型如守护进程)
七、Linux 进程相关命令
PID:进程的ID号
PPID :父进程ID号
父进程:产生子进程的进程称为父进程
子进程:父进程产生出来的新进程即为该父进程的子进程
ps -aux | grep ./a.out
| : 管道 :前面命令的输出作为后面命令的输入
grep : 字符串查找:在输入中查找和后面字符串相关的数据
命令 | 功能 |
---|---|
ps -aux | 查看进程相关参数:PID、状态、CPU占有率、内存占有率 |
ps -ef | 查看该进程的ID和父进程ID |
pstree | 查看进程的产生关系 |
pstree -p | 查看进程的产生关系(有PID号) |
top | 动态查看进程的相关参数:CPU占有率、内存占有率 |
kill | 向进程发送信号 |
kill -l | 查看系统支持的信号名称PID |
kill -x | 向进程发送信号(x),让进程的状态发生变化 ( x 为信号的编号 / 信号的名称PID) |
jobs | 查看当前终端的后台进程 |
fg | 让后台进程切换成前台进程 |
kill 示例:
kill -9 PID # 强制结束
kill -SIGKILL PID # 强制结束
kill -STOP PID # 暂停
八、进程编程
1. 进程创建:fork()
#include <sys/types.h>
#include <unistd.h>
pid_t pid = fork(void);
功能:拷贝父进程,生成一个新的子进程
特点:
子进程拷贝父进程 0~3G 虚拟内存空间
PCB (进程控制块)部分信息拷贝(PID 不同)
父子进程栈区、数据区、文本区、堆区完全独立,数据不共享
要想共享数据,需要使用进程间通信方式实现
返回值:
父进程中返回 子进程 PID
子进程中返回 0
失败返回 -1
2. 获取进程信息
pid_t getpid(void); // 获取当前进程 PID
pid_t getppid(void); // 获取父进程 PID
2.进程调度:(由操作系统完成)
3. 进程消亡
1.进程退出:return、exit()相关函数
1)main中return
2) exit ()、_exit() :结束一个进程
exit (0) : 正常退出
exit (非0) :由于进程产生了某种问题,需要主动退出进程
2.回收资源空间:wait()、waitpid()
4. 回收子进程
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
九、僵尸进程
1. 回收资源空间:wait()、waitpid()
僵尸进程:进程退出后,但其资源空间未被父进程回收
如何避免僵尸进程产生:
1. 子进程退出后,父进程及时为其回收资源空间
2. 让该进程成为一个孤儿进程,结束时被操作系统中的系统进程回收
孤儿进程:父进程先消亡,其对应的子进程成为一个孤儿进程,会被系统进程所收养
(守护类的进程)