首页 > 解决方案 > waitpid 没有给我一致的结果

问题描述

编辑:我应该首先澄清一下,当 waitpid 不起作用时,它不适用于所有进程。按照建议,我打印了 waitpid 的返回值并收到了有趣的结果。首先,在不成功的运行过程中,即使 WIFEXITED(stats) 返回 1,waitpid() 也会返回 0。子进程怎么可能没有状态变化但返回已完成?

其次,我使用了一个虚拟程序,它每 1 秒打印出一个字符串参数并持续指定的次数。(这就是我跟踪程序是否完成的方式)。我注意到在成功运行期间,在上下文切换期间没有打印出 waitpid 值,而是在所有进程完成运行之后。

像这样:(这里假设每个 prog 需要 2 个配额才能完成)“prog1 run”“prog2 run”“prog3 run”“prog1 run”“prog2 run”“prog3 run”waitpid:0 waitpid:0 waitpid:0 ...

另一方面,一次不成功的运行给了我这个:“prog1 run”waitpid:0 检测到程序终止“prog2 run”waitpid:0 检测到程序终止“prog3 run”waitpid: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;

标签: cwaitpid

解决方案


这种代码:

        PID = fork();
        if (PID != 0) 
        {   << then running parent process or error occurred
            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;
        }

如果调用fork()成功,则终止子进程。可能不是你想要的。


推荐阅读