手机网站改版公司,陕西网站建设的目的,wordpress安卓显示图片,下载电商平台app个人主页#xff1a;chian-ocean
文章专栏-Linux
前言#xff1a; 当一个进程发起某种操作#xff08;如I/O请求、信号、锁的获取等#xff09;#xff0c;但该操作需要的资源暂时不可用时#xff0c;进程会被操作系统挂起#xff0c;进入“等待队列”或“阻塞状态”。…个人主页chian-ocean
文章专栏-Linux
前言 当一个进程发起某种操作如I/O请求、信号、锁的获取等但该操作需要的资源暂时不可用时进程会被操作系统挂起进入“等待队列”或“阻塞状态”。在此期间进程不占用CPU但仍保留其内存、文件描述符等资源 进程等待的必要性
僵尸进程的存在
僵尸进程的成因
当子进程终止后它的退出状态需要由父进程通过调用 wait() 或 waitpid() 系统调用回收。如果父进程未回收子进程的退出状态子进程会以“僵尸进程”的形式保留在进程表中。
特征
在 Linux 系统中可以用 ps 命令查看僵尸进程的状态为 ZZombie。僵尸进程是操作系统保留的一个条目主要用于父进程检查子进程的退出状态。
如下 从图片中可以看到一个典型的 僵尸进程 的现象
进程 27864 被强制终止kill -9 27864但它的父进程27863没有调用 wait() 或 waitpid() 来回收其子进程的退出状态。因此27864 被标记为 defunct 状态即僵尸进程。ps 输出的 STAT 列中显示 Z这是僵尸进程的状态标识。
进程等待
进程等待是操作系统中一种重要的状态指的是某个进程由于资源不足或条件未满足暂时无法继续执行而被挂起的现象。
使用 wait() 或 waitpid() 回收子进程
wait ( )
参数 int *status用于保存子进程的状态信息如退出码或终止信号。如果不需要获取子进程状态可以将其传入 NULL。
返回值
成功 返回已终止的子进程的 PID。 失败 返回 -1并设置 errno。常见错误包括 ECHILD当前进程没有子进程。EINTR调用被信号中断。
wait() 的作用
阻塞父进程 wait() 会阻塞父进程直到任意一个子进程状态发生变化通常是终止。 回收子进程资源 子进程终止后其资源仍然保留在系统中直到父进程调用 wait() 或 waitpid() 回收它。如果父进程不调用 wait() 或 waitpid()子进程会变成 僵尸进程。
示例
#includeiostream
#includeunistd.h
#include sys/types.h
#include sys/wait.husing namespace std;void childtast()
{for(int i 0; i 10; i) // 循环打印从 0 到 9 的数字{cout i endl; // 输出当前的循环变量 i}sleep(3); // 睡眠 3 秒模拟子进程的运行延迟
}int main()
{pid_t id fork(); // 创建子进程cout id : id endl;if(id 0) // 判断是否是子进程{sleep(3); // 子进程先睡眠 3 秒childtast(); // 子进程调用 childtast()打印数字并睡眠}// 父进程等待任意一个子进程终止pid_t ret wait(NULL); // 父进程调用 wait()阻塞等待子进程终止if(ret id) // 判断 wait() 返回的进程 ID 是否是创建的子进程 ID{cout ret : ret endl; // 输出子进程的 IDcout wait success endl; // 输出等待成功的消息}sleep(3); // 父进程再睡眠 3 秒模拟延迟return 0;
}fork() 创建子进程
父进程和子进程同时运行。父进程的 id 是子进程的 PID子进程的 id 是 0。
子进程的任务
子进程先睡眠 3 秒然后执行 childtast()打印 0 到 9。
父进程的等待
父进程调用 wait(NULL)阻塞自身直到子进程终止。当子进程完成任务并退出后wait() 返回子进程的 PID。
父进程的后续操作
父进程输出子进程的PID和等待成功的消息。父进程再睡眠 3 秒后退出。
waitpid ( )
waitpid() 是 wait() 的增强版本提供了更灵活的功能允许父进程
等待特定的子进程。非阻塞等待子进程。获取子进程的状态如退出状态或被信号终止。
pid_t waitpid(pid_t pid, int *status, int options);参数说明 pid pid 0等待特定的子进程指定的 PID。 pid 0等待与当前进程同一个进程组的任意子进程。 pid -1等待进程组 ID 为 |pid| 的任意子进程。 wait(NULL) //等价于 waitpid(-1,NULL,0); pid -1等效于 wait()等待任意子进程。
status 字段的结构
status
指向一个整数的指针用于存储子进程的状态信息退出状态、信号等。若不关心状态信息可将其设为 NULL。
在 Linux 系统中status 是一个整数表示子进程状态的多种可能性底层通过位字段表示
位字段含义位 0-7子进程退出的信号或退出码低 8 位。位 8-15退出状态高 8 位存储正常退出码。位 16-23暂停信号编号。
代码解析字段
#includeiostream
#includeunistd.h
#includesys/types.h
#includesys/wait.h
using namespace std;
int main()
{ pid_t id fork(); cout id : id endl; if(id 0) { sleep(3); exit(1); } int status; pid_t ret waitpid(-1,status,0); if(ret id) {cout ret : ret endl; cout wait success endl; } cout status : status endl;cout 退出码 ((status 8) 0xff ) 信号码 (status 0x7f) endl;return 0;
}完整运行流程
fork() 创建子进程
父进程创建子进程并返回子进程的 PID。
子进程逻辑
子进程休眠 3 秒后正常退出退出码为 1。
父进程逻辑
父进程调用 waitpid() 阻塞等待子进程终止。获取子进程的状态信息并解析退出码和信号码。
父进程输出状态信息
输出子进程的 PID、状态值、退出码和信号码。
解析逻辑 退出码 (status 8) 0xff获取高 8 位的退出码。 信号码 status 0x7f获取低 7 位的信号码. 示例1进程正常退出的退出码。 示例2提取被9号信号杀死的进程信号码 id:1667 // 父进程输出子进程的 PID 是 1667
id:0 // 子进程输出表明当前是子进程
ret:1667 // 父进程成功等待到子进程结束返回子进程 PID
wait success // 父进程确认子进程终止
status :9 // 父进程获取子进程状态值为 9
退出码0 信号码9 // 父进程解析状态值// - 退出码 0子进程未通过 exit() 返回退出码// - 信号码 9子进程被 SIGKILL 信号终止库中提供的宏替换 解析退出码和信号编号 WIFEXITED(status) 如果为真表示子进程正常退出其退出码存储在高 8 位。使用 (status 8) 0xff 提取退出码。 WEXITSTATUS(status) 获取退出码的宏等价于 (status 8) 0xff。必须确保 WIFEXITED(status) 为真后使用。
解析退出码和信号编号
WIFEXITED(status) 如果为真表示子进程正常退出其退出码存储在高 8 位。使用 (status 8) 0xff 提取退出码。 WEXITSTATUS(status) status 0x7f 获取退出码的宏必须确保 WIFEXITED(status) 为真后使用。
options参数介绍
阻塞与非阻塞
特性阻塞非阻塞进程状态等待资源时挂起无法执行其他任务。立即返回不会挂起进程可执行其他任务。适用场景简单任务、对实时性要求不高的任务。多任务并发、实时性要求高的任务。复杂性实现简单逻辑清晰。逻辑复杂需要轮询或回调处理资源状态。CPU 使用不浪费 CPU 资源进程处于挂起状态。需要轮询资源状态可能增加 CPU 占用。资源管理等待资源的管理交由操作系统处理。需要程序主动检查资源状态增加开发复杂度。
options
用于指定额外的选项 0阻塞等待。WNOHANG非阻塞等待。WUNTRACED返回暂停的子进程状态子进程因 SIGSTOP 信号暂停。WCONTINUED返回恢复运行的子进程状态子进程因 SIGCONT 信号继续运行。
WNOHANG
非阻塞模式 如果没有子进程终止waitpid() 会立即返回而不是阻塞父进程。 返回值 如果有子进程状态变化则返回子进程的 PID。如果没有子进程状态变化则返回 0。
非阻塞轮询
#include iostream
#include unistd.h
#include sys/types.h
#include sys/wait.h
#include chrono
#include thread
using namespace std;
int main() {pid_t pid fork(); // 创建子进程if (pid 0) {// 子进程逻辑cout Child process running... endl;sleep(5); // 模拟子进程任务延迟 5 秒cout Child process exiting... endl;exit(42); // 子进程以退出码 42 正常退出} else if (pid 0) {// 父进程逻辑int status;while (true) {pid_t ret waitpid(-1, status, WNOHANG); // 非阻塞检查子进程状态if (ret 0) {// 子进程尚未终止父进程继续其他工作cout Child process still running. Parent doing other work... endl;this_thread::sleep_for(chrono::seconds(1)); // 模拟父进程任务} else if (ret 0) {// 子进程已终止解析状态if (WIFEXITED(status)) {cout Child process ret exited with code WEXITSTATUS(status) endl;} else if (WIFSIGNALED(status)) {cout Child process ret was terminated by signal WTERMSIG(status) endl;}break; // 结束轮询} else {// waitpid 出错perror(waitpid failed);break;}}} else {// fork 失败perror(fork failed);return 1;}return 0;
}执行结果 多进程下的进程等待
阻塞等待多个子进程
示例代码等待所有子进程完成
#include iostream
#include unistd.h
#include sys/types.h
#include sys/wait.h
using namespace std;int main() {// 创建多个子进程for (int i 0; i 3; i) {pid_t pid fork();if (pid 0) {// 子进程cout Child i (PID: getpid() ) running... endl;sleep(2 i); // 每个子进程休眠不同时间cout Child i (PID: getpid() ) exiting... endl;exit(i); // 子进程以其序号为退出码}}// 父进程等待所有子进程完成int status;while (true) {pid_t ret wait(status); // 阻塞等待任意一个子进程结束if (ret -1) {// 没有子进程可等待时退出循环cout All child processes have finished. endl;break;// 解析子进程状态if (WIFEXITED(status)) {cout Child process ret exited with code: WEXITSTATUS(status) endl;} else if (WIFSIGNALED(status)) {cout Child process ret was terminated by signal: WTERMSIG(status) endl;}}return 0;
}代码执行 非阻塞轮询等待多个子进程
示例代码非阻塞等待多个子进程
通过 waitpid() 配合 WNOHANG 实现父进程的非阻塞轮询定期检查是否有子进程完成。
#include iostream
#include unistd.h
#include sys/types.h
#include sys/wait.h
#include chrono
#include thread
using namespace std;int main() {// 创建多个子进程for (int i 0; i 3; i) {pid_t pid fork();if (pid 0) {// 子进程cout Child i (PID: getpid() ) running... endl;sleep(2 i); // 每个子进程休眠不同时间cout Child i (PID: getpid() ) exiting... endl;exit(i); // 子进程以其序号为退出码}}// 父进程非阻塞轮询等待所有子进程完成int status;int completed 0; // 已完成的子进程计数while (completed 3) {pid_t ret waitpid(-1, status, WNOHANG); // 非阻塞检查子进程状态if (ret 0) {// 有子进程状态变化completed;if (WIFEXITED(status)) {cout Child process ret exited with code: WEXITSTATUS(status) endl;} else if (WIFSIGNALED(status)) {cout Child process ret was terminated by signal: WTERMSIG(status) endl;}} else if (ret 0) {// 没有子进程状态变化父进程继续其他工作cout No child process exited yet. Parent doing other work... endl;this_thread::sleep_for(chrono::seconds(1)); // 模拟其他任务} else {// 错误处理perror(waitpid failed);break;}}cout All child processes have finished. endl;return 0;
}
代码执行