Получи пид от брата - PullRequest
       58

Получи пид от брата

0 голосов
/ 20 апреля 2020

Я хочу иметь родительский процесс и три дочерних процесса. Я хочу, чтобы эти дочерние процессы знали pids других дочерних процессов. Проблема в том, что когда я делаю fork, а затем делаю это снова, вторая ветвь также выполняется в дочернем процессе, создавая дополнительный процесс (или я так думаю). Как я мог решить это?

Спасибо.

Ответы [ 2 ]

2 голосов
/ 20 апреля 2020

Родитель должен разветвляться три раза, дети не должны разветвляться. Таким образом, родитель узнает pids всех трех детей.

После разветвления вам понадобится какой-то отдельный канал связи, по которому родитель может передать эти pids всем детям. Простым способом было бы открыть канал (см. pipe(2)) перед разветвлением каждого дочернего элемента, чтобы дочерний объект наследовал дескриптор файла канала (по крайней мере, конец чтения), а родительский элемент оставлял конец записи. Затем попросите родителя отправить три пида по каждой трубе и закрыть его.

Пример кода (длинный, но это характер C):

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#define NUM_CHILDREN 3

/* Entry point for the child processes */
int child_main(int pipe_read_end) {
  pid_t my_pid = getpid();

  /* Read child pids from pipe */
  int child_pids[NUM_CHILDREN];
  unsigned int bytes_read = 0;
  while (bytes_read < sizeof(child_pids)) {
    ssize_t result = read(pipe_read_end, ((unsigned char *) child_pids) + bytes_read, sizeof(child_pids) - bytes_read);
    if (result < 0) {
      perror("error reading from pipe");
      return 1;
    } else if (result == 0) {
      fprintf(stderr, "unexpected end of file\n");
      return 1;
    } else {
      bytes_read += result;
    }
  }
  close(pipe_read_end);

  /* Do something useful with these child pids */
  for (int i = 0; i < NUM_CHILDREN; i++) {
    printf("Child %d received sibling pid %d\n", my_pid, child_pids[i]);
  }

  return 0;
}

/* Entry point for the parent process. */
int main() {
  int child_pids[NUM_CHILDREN];
  int pipe_write_ends[NUM_CHILDREN];
  for (int i = 0; i < NUM_CHILDREN; i++) {
    /* Create the pipe for child i */
    int pipefd[2];
    if (pipe(pipefd)) {
      perror("error creating pipe");
      return 1;
    }
    int pipe_read_end = pipefd[0];
    int pipe_write_end = pipefd[1];

    /* Fork child i */
    pid_t child_pid = fork();
    if (child_pid < 0) {
      perror("error forking");
      return 1;
    } else if (child_pid == 0) {
      printf("Child %d was forked\n", getpid());
      close(pipe_write_end);
      return child_main(pipe_read_end);
    } else {
      printf("Parent forked child %d\n", child_pid);
      close(pipe_read_end);
      pipe_write_ends[i] = pipe_write_end;
      child_pids[i] = child_pid;
    }
  }

  /* Send pids down the pipes for each child */
  for (int i = 0; i < NUM_CHILDREN; i++) {
    unsigned int bytes_written = 0;
    while (bytes_written < sizeof(child_pids)) {
      ssize_t result = write(pipe_write_ends[i], ((unsigned char *) child_pids) + bytes_written, sizeof(child_pids) - bytes_written);
      if (result < 0) {
        perror("error writing to pipe");
        return 1;
      } else {
        bytes_written += result;
      }
    }
    close(pipe_write_ends[i]);
  }

  /* Wait for children to exit */
  for (int i = 0; i < NUM_CHILDREN; i++) {
    if (waitpid(child_pids[i], 0, 0) < 0) {
      perror("error waiting for child");
      return 1;
    }
  }
}

Как указывает @PSkocik в их ответе вы, вероятно, не должны этого делать. ОС может повторно использовать пиды, поэтому у детей нет возможности узнать, что их родные братья все еще на самом деле относятся к их родным братьям; только родитель может быть уверен, потому что он должен wait для каждого pid, прежде чем его можно будет повторно использовать.

Однако этот же механизм можно использовать для других форм IP C (межпроцессное взаимодействие ); Вы можете, например, использовать его для непосредственного создания каналов между дочерними элементами.

1 голос
/ 20 апреля 2020

Вы можете использовать совместно используемую память или какой-либо другой вид IP C для передачи PID, но вам, вероятно, даже не следует пытаться.

PID подлежат переработке, и вы можете знать только наверняка если PID относится к процессу, который, как вы думаете, относится к нему, относится ли этот PID к вашему дочернему процессу (потому что тогда вы можете знать, если вы wait редактировали его или нет).

В противном случае, PID (не для детей) - это необычные ссылки, которые в основном используются только для хакерской отладки.

...