赞
踩
引入:
为什么?是什么?怎么办
进程等待是指父进程暂停自己的执行,直到某个特定的子进程结束或发生某些特定的事件。
wait 函数
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int* status);
测试:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> int main ( void ) { pid_t id = fork(); if (id == 0) { // child while (1) { printf("我是子进程,我正在运行... Pid: %d\n", getpid()); sleep(1); } } else { printf("我是父进程: pid: %d,我将耐心地等待子进程!\n", getpid()); sleep(20); // 为了便于观察,我们让父进程休眠20s // 苏醒后,父进程执行 wait,耐心地等待子进程 pid_t ret = wait(NULL); // 暂且将status参数设置为NULL if (ret < 0) { printf("等待失败!\n"); } else { printf("等待成功!\n"); // 此时 Z → X } sleep(20); // 子进程退出后,再让父进程存在一段时间 } }
为什么是交替型,不是一个执行完?//了解循环的细节
在 fork
创建子进程后,父进程会首先执行并打印这条信息,其中 <父进程的pid>
是父进程的进程ID。截不下就没截了
通过这种方式,父进程和子进程能够并发地执行各自的任务,并且我们通过延迟父进程的退出能观察到子进程的连续活动。
父进程打印:
yamlCopy code
我是父进程: pid: 1234,我将耐心地等待子进程!
子进程每秒打印一次:
yamlCopy code
我是子进程,我正在运行... Pid: 5678
(此循环持续到子进程被终止)
通过终端输入 kill 5678
终止子进程。
父进程20秒后苏醒并等待子进程结束后,打印:
textCopy code
等待成功!
之后,父进程再休眠20秒并继续存在一段时间后退出
刚才讲的 wait 并不是主角,因为其功能比较简单,在进程等待时用的更多的是 waitpid
waitpid 可以把 wait 完全包含,wait 是 waitpid 的一个子功能。
参数:
pid
:要等待的子进程的进程ID。根据传入的值可以指定等待任何子进程、特定进程ID的子进程、任何同一进程组的子进程或者任何同一会话的子进程。
pid
大于零,waitpid
将等待指定进程ID的子进程结束。pid
等于 -1,waitpid
将等待任意子进程结束,等同于 wait
函数。status
:一个指向整型的指针,是一个输出型参数,它将用于存储子进程的终止状态。
options
:用于指定等待行为的附加选项。
返回值:
waitpid
成功,返回值是已终止子进程的进程ID。errno
变量来指示具体错误原因。Z状态,其本质上就是将自己的 task_struct 维护起来(代码可以释放,但是 task_struct 必须维护)。所谓的 wait/waitpid 的退出信息,实际上就是从子进程的 task_struct 中拿出来的,即 从子进程的 task_struct 中拿出子进程退出的退出码,拷贝到父进程中
该参数是一个 输出型参数 (即通过调用该函数,从函数内部拿出来特定的数据)。整数的低 16 位,其中又可以分为 最低八位 和 次低八位(具体细节看图):
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> int main ( void ) { pid_t id = fork(); if (id == 0) { int cnt = 5; // 循环5次 // child while (1) { // 五秒之内运行状态 printf("我是子进程,我正在运行... Pid: %d\n", getpid()); sleep(1); // 五秒之后子进程终止 cnt--; if (cnt == 0) { break; } } exit(233); // 方便辨识,退出码我们设置为233,这是我们的预期结果 } else { printf("我是父进程: pid: %d,我将耐心地等待子进程!\n", getpid()); // ***** 使用waitpid进行进程等待 int status = 0; // 接收 waitpid 的 status 参数 pid_t ret = waitpid(id, &status, 0); if (ret > 0) { // 等待成功 printf ( "等待成功,ret: %d, 我所等待的子进程退出码: %d\n", ret, (status>>8)&0xFF ); } } }
status 并不是整体使用的,而是区域性使用的,我们要取其次低八位。我们可以用 位操作 来完成,将 status右移八位再按位与上 0XFF,即 (status>>8)&0xFF ,就可以提取到 status 的次低八位了。
waitpid 经过系统调用,来读取子进程的pcb(eg. task_st…),这是为什么呢
操作系统不相信任何人,父进程用户无法直接读取子进程的 pcb ,要通过系统调用的接口
它是操作系统在进程收到某些信号而终止运行时,将此时进程地址空间的内容以及有关进程状态的其他信息写出的一个磁盘文件。目前只需要知道,该信息是用于调试的。
刚才我们讲的 wait/waitpid 和次低八位的时侯,都是关于进程(exit) 的 正常退出。
如果进程 异常退出 呢?我们来模拟一下进程的异常退出。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。