【发布时间】:2020-02-25 16:10:04
【问题描述】:
编辑:我首先要澄清的是,当 waitpid 不起作用时,它不适用于所有进程。 按照建议,我打印了 waitpid 的返回值并收到了有趣的结果。首先,在不成功的运行过程中,即使WIFEXITED(stats)返回1,waitpid()也会返回0。子进程怎么可能没有状态变化但返回完成?
其次,我使用了一个虚拟程序,它每 1 秒打印出一个字符串参数并持续指定的次数。 (这就是我跟踪程序是否完成的方式)。我注意到在成功运行期间,在上下文切换期间并没有打印出 waitpid 值,而是在所有进程完成运行之后。
像这样:(这里假设每个 prog 需要 2 个配额才能完成) “prog1 运行” “prog2 运行” “prog3 运行” “prog1 运行” “prog2 运行” “prog3 运行” 等待PID:0 等待PID:0 等待PID:0 ...
另一方面,一次不成功的运行给了我这个: “prog1 运行” 等待PID:0 检测到程序终止 “prog2 运行” 等待PID:0 检测到程序终止 “prog3 运行” 等待PID:0 检测到程序终止
TLDR:waitpid(child_PID, stat, WNOHANG) 是否可以在同一程序的不同运行中给出不同的 WIFEXITED(stat)?
我正在编写循环调度程序。父进程派生出 n 个子进程,每个子进程在调度程序中运行一个进程。使用信号 SIGCONT 和 SIGSTOP 以及 usleep() 函数,父进程能够为每个子进程分配指定的时间配额,以便在一个循环中按顺序运行。 在每个配额结束时,父进程会检查是否有任何进程已完成。它使用 waitpid(child_PID, stat, WNOHANG);然后是 WIFEXITED(stat)。如果进程已完成,则父进程在后续循环中不会再为该进程分配任何时间配额。
但是,我注意到,在我运行代码的每隔一段时间,WIFEXITED(stat) 在第一个配额周期后给我一个 1,即使我认为我已经确保每个进程的运行时间都应该比所述配额长得多。我知道程序不应该完成,因为我的测试程序涉及在退出之前打印指定数量的行。最奇怪的是,WIFEXITED 每次运行都给我错误的结果,而且在第一个周期。
我已经包含了代码,以防有人有足够的耐心阅读它。希望不需要阅读代码来理解问题。对于那些愿意阅读它的人,谢谢,这意味着很多,也许您可能知道为什么我的程序没有终止?当 t 正确运行时,它会正确调度所有进程并运行它们直到所有进程都终止,但不会自行终止。
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <stdbool.h>
int main(int argc, char *argv[]) {
int tick_interval = 10000;
char opt;
while ((opt = getopt(argc, argv, "t:")) != -1) {
switch (opt) {
case 't':
tick_interval = atoi(optarg);
break;
default:
goto usage;
}
}
if (optind >= argc) {
goto usage;
}
char *filepath = argv[optind];//filepath to textfile containing name of programs and arguments.
int n;
FILE * fp;
char * line = NULL;
size_t len = 0;
ssize_t read;
printf("parent PID: %d\n", getpid());
fp = fopen(filepath, "r");
if (fp == NULL)
exit(EXIT_FAILURE);
int PID;
int *prog_tracker = malloc(0);
int line_counter = 0;
int word_counter;
int word_length;
char ***lines = malloc(0);
while ((read = getline(&line, &len, fp)) != -1) {
//printf("round %d\n", line_counter);
word_counter = 0;
word_length = 0;
lines = realloc(lines, (++line_counter) * sizeof(char**));
lines[line_counter - 1] = malloc(0);
int char_counter;
bool is_new = 1;
for (char_counter = 0; char_counter < read; char_counter ++) {
if (is_new) {
is_new = 0;
lines[line_counter - 1] = realloc(lines[line_counter - 1], ++word_counter * sizeof(char*));
lines[line_counter - 1][word_counter - 1] = malloc(0);
}
lines[line_counter - 1][word_counter - 1] = realloc(lines[line_counter - 1][word_counter - 1], ++word_length * sizeof(char));
if (line[char_counter] == ' '||line[char_counter] == '\0' || line[char_counter] == '\n' || line[char_counter] == EOF) {
is_new = 1;
lines[line_counter - 1][word_counter - 1][word_length - 1] = '\0';
word_length = 0;
} else {
lines[line_counter - 1][word_counter - 1][word_length - 1] = line[char_counter];
}
}
//first line states number of cores to be used. To be implemented. Ignored for now.
if (line_counter != 1) {
PID = fork();
if (PID != 0) {
printf("PID: %d created at: %d\n", PID, line_counter);
kill(PID, SIGSTOP);
prog_tracker = realloc(prog_tracker, (line_counter - 1) * sizeof(int));
prog_tracker[line_counter - 2] = PID;
} else {
char *arguments[word_counter + 1];
int counter;
for (counter = 0; counter < word_counter; counter ++) {
arguments[counter] = lines[line_counter - 1][counter];
}
arguments[word_counter] = NULL;
execv(arguments[0], arguments);//child processes implement processes in file.
break;
}
}
}
free(lines);
fclose(fp);
if (line)
free(line);
if (PID != 0) {
printf("parent running %d\n", getpid());
int proc_num = 0;
int prog_num = line_counter - 1;
printf("prog_num: %d\n", prog_num);
while (prog_num != 0) { //The while loop should break when all programs have finished, but it does not.
kill(prog_tracker[proc_num], SIGCONT);
usleep(tick_interval * 1000);
kill(prog_tracker[proc_num], SIGSTOP);
int stat;
printf("status: %d", waitpid(prog_tracker[proc_num], &stat, WNOHANG)); //I now print out the return of waitpid.
printf("%d\n", WIFEXITED(stat));
if (WIFEXITED(stat)) {
//printf("%d\n", WIFEXITED(stat));
printf("program termination detected\n");
prog_tracker[proc_num] = 0;
prog_num -= 1;
printf("processes left %d\n", prog_num);
}
proc_num = (++proc_num) % (line_counter - 1);
while(prog_tracker[proc_num] == 0) {
proc_num = (++proc_num) % (line_counter - 1);
}
}
printf("All programs ended.");//This never gets printed!
}
return 0;
【问题讨论】:
-
在尝试使用
stat之前,您应该检查waitpid()的返回值以确保它成功。 -
对于相对较大的程序,很难发现可能的错误。您应该简化代码以创建minimal reproducible example。我建议用固定值替换命令行参数和输入文件的处理。添加调试输出以查看
waitpid的结果属于哪个PID。检查所有函数的返回值,可能某个函数报错。 -
贴出的代码无法编译!除其他外,它缺少最后一个
} -
发布的代码导致编译输出大量警告,包括这个关键警告:untitled1.c:108:20: warning: 'proc_num' 上的操作可能未定义 [-Wsequence-点] 并再次在第 110 行
-
OT:建议在编译时始终启用警告,然后修复这些警告。 (对于
gcc,至少使用:-Wall -Wextra -Wconversion -pedantic -std=gnu11)注意:其他编译器使用不同的选项来产生相同的结果