题目
利用 fork() 创建 3 个子进程:第 1 个子进程打印 “Hello World”;第 2 个子进程计算 2 的 8 次方,并且打印结果;第 3 个子进程尝试打印 5 / 0 的结果。父进程利用轮询方法非阻塞式地等待 3 个子进程结束,并且打印子进程的结束信息。
点拨
waitpid() 等待一个指定的进程或进程组的状态改变。默认情况下,它只在指定的进程(组)被终止后返回。可以通过传递相应的参数来改变其行为。该函数返回状态改变的子进程 ID。若出错,返回 -1。如果指定了参数(宏)WNOHANG,且第一个参数 pid 指定的一个或多个子进程存在,但未改变其状态,则返回 0。
WNOHANG | WUNTRACED | WCONTINUED 指定 waitpid() 在无子进程退出时立刻返回、在子进程被暂停时返回、在子进程因为 SIGCONT 继续运行时返回。
宏 WIFEXITED 判定指定的状态变量是否表示进程正常退出。WEXITSTATUS 可以从状态变量读出子进程的退出状态。
WIFSIGNALED 表示进程是否被信号终止。配合 WTERMSIG 可以获得使进程(异常)终止的信号。
WIFSTOPPED 表示进程是否被暂停。配合 WSTOPSIG 可以获得使进程暂停的信号。
源代码
#include <cmath>
#include <cstring>
#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
using namespace std;
const size_t CHILDREN_COUNT = 3;
pid_t child[CHILDREN_COUNT];
pid_t terminate_child[CHILDREN_COUNT];
int end_state[CHILDREN_COUNT];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
child[0] = fork();
if (child[0] == 0) {
cout << getpid() << ": Hello World" << endl;
return 0;
}
child[1] = fork();
if (child[1] == 0) {
cout << getpid() << ": pow(2, 8) = " << pow(2, 8) << endl;
return 0;
}
child[2] = fork();
if (child[2] == 0) {
cout << getpid() << ": 5 / 0 = " << 5 / 0 << endl;
return 0;
}
for (size_t i = CHILDREN_COUNT, j = 0; i; ++j) {
if (j == CHILDREN_COUNT) j = 0;
terminate_child[j] = waitpid(child[j], &end_state[j], WNOHANG | WUNTRACED | WCONTINUED);
if (terminate_child[j] > 0) {
cout << "--------------------------------" << endl;
cout << "Child process " << terminate_child[j] << " has ended. " << endl;
if (WIFEXITED(end_state[j])) cout << "Normally exited. Status: " << WEXITSTATUS(end_state[j]) << endl;
else if (WIFSIGNALED(end_state[j])) cout << "EXCEPTION: Killed by signal " << WTERMSIG(end_state[j]) << ": " << strsignal(WTERMSIG(end_state[j])) << endl;
else if (WIFSTOPPED(end_state[j])) cout << "Paused by signal " << WSTOPSIG(end_state[j]) << endl;
cout << "Remaining child(ren) count: " << --i << endl;
cout << "--------------------------------" << endl;
}
}
return 0;
}