Как написать обратно в трубу родителей?

0

Предположим, у меня есть следующий код. Можно ли написать от ребенка обратно родитель? Могу ли я сделать это через ту же трубу, мифпип? Нужна ли мне другая функция ожидания?

int mypipe[2];
int i, pid;

pipe (mypipe);
value = fork ();
if (value == -1)
  {
    exit (0);
  }
else if (value == 0)
  {
    read (mypipe[0], (char *) &i, sizeof (int));
    cout << "i = " << i << endl;
    exit (0);
  }
else
  {
    i = 7;
    write (mypipe[1], (char *) &i, sizeof (int));
    wait (&pid);
  }
Теги:
posix
fork

3 ответа

0

До тех пор, пока вы каким-либо образом контролируете синхронизацию между двумя процессами, вы можете использовать один канал для записи от родителя к дочернему и от дочернего к родительскому. Например:

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

int main(void)
{
    int mypipe[2];
    int i, pid;
    pipe(mypipe);
    pid = fork();
    if (pid == -1)
    {
        perror("Cannot fork");
        return 1;
    }
    else if (pid == 0)
    {
        read(mypipe[0], &i, sizeof(int));
        printf("child: i = %d\n", i);
        i += 13;
        write(mypipe[1], &i, sizeof(int));
    }
    else
    {
        i = 7;
        write(mypipe[1], &i, sizeof(int));
        int status;
        int corpse = wait(&status);
        read(mypipe[0], &i, sizeof(int));
        printf("parent: i = %d (child = %d = %d; status = 0x%.4X)\n",
               i, pid, corpse, status);
    }
    return 0;
}

Пробный пробег:

child: i = 7
parent: i = 20 (child = 62299 = 62299; status = 0x0000)

Синхронизация здесь заключается в том, что родительский процесс ждет, пока ребенок умрет, прежде чем читать записку о самоубийстве от ребенка.

Это редко используется - вы обычно создаете две отдельные трубы, одну для родителя, чтобы писать ребенку, а другая - для ребенка, чтобы написать родителям - потому что это упрощает синхронизацию. Единственная проблема, с которой вы должны быть осторожны, - это не заполнение труб, чтобы родительский объект был заблокирован, пытаясь записать его дочернему элементу, когда ребенок заблокирован, пытаясь записать родительский (тупик). Если у вас простой полудуплексный протокол (так что каждый процесс знает, когда другой завершил свое текущее сообщение), или если у вас есть отдельные потоки чтения и записи в каждом процессе, вы можете избежать взаимоблокировки.

Обратите внимание, что некоторые системы (BSD) обеспечивают двунаправленные каналы. Сокеты также являются двунаправленными каналами связи.

0

Да, вы можете использовать трубу так, чтобы родитель записывал и ребенок читал, или чтобы ребенок записывал и родитель читал. Трубы являются однонаправленными, поэтому вы не можете делать то и другое (если вы хотите сделать то и другое, вам понадобится socketpair).

С manpage:

pipe() создает канал, однонаправленный канал данных, который может использоваться для межпроцессного взаимодействия. Массив pipefd используется для возврата двух дескрипторов файлов, ссылающихся на концы трубы. pipefd[0] относится к считываемому концу трубы. pipefd[1] относится к концу записи трубы. Данные, записанные на конец записи, буферизуются ядром до тех пор, пока они не будут прочитаны с конца считывания. Для получения дополнительной информации см. pipe(7).

Я очистил вашу программу и скомпилировал ее в C (no cout), и она работает:

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

int mypipe[2];
int i, pid;

int
main (int argc, char **argv)
{
  int value;
  pipe (mypipe);
  value = fork ();
  if (value == -1)
    {
      perror ("Cannot fork");
      exit (1);
    }
  else if (value == 0)
    {
      read (mypipe[0], &i, sizeof (int));
      printf ("i = %d\n", i);
      wait (&pid);
      exit (0);
    }
  else
    {
      i = 7;
      write (mypipe[1], &i, sizeof (int));
      exit (0);
    }
}

Как вы можете видеть, никаких существенных изменений не произошло (за исключением того, что по какой-то причине вы пытались написать int, используя указатель char который на малой машине будет писать 0).

Ваша программа читает дочерние элементы и записывает их в родительский.

Здесь версия, которая читается в родительском и записывает в дочерний элемент, также отлично работает. Как вы можете видеть, это просто вопрос об обмене чтениями и записью бит вокруг.

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

int mypipe[2];
int i, pid;

int
main (int argc, char **argv)
{
  int value;
  pipe (mypipe);
  value = fork ();
  if (value == -1)
    {
      perror ("Cannot fork");
      exit (0);
    }
  else if (value == 0)
    {
      i = 7;
      write (mypipe[1], &i, sizeof (int));
      exit (0);
    }
  else
    {
      read (mypipe[0], &i, sizeof (int));
      printf ("i = %d\n", i);
      wait (&pid);
      exit (0);
    }
}
  • 0
    Вы не можете wait() в дочернем процессе, чтобы родитель умер. В системах Unix родители могут ждать смерти своих детей, но не наоборот.
  • 0
    К сожалению, я слишком много поменялся там и вернул wait родителю. Тестовый сценарий сработал, потому что read не завершится до того, как write будет завершена.
Показать ещё 2 комментария
0

Трубы однонаправленные. Существует один конец записи и один конец. Если у вас есть несколько процессов (дочерний и родительский), которые читают этот канал, не определено, какие сообщения будут прочитаны каждым.

Да, ребенок может писать в (обычно канал "родитель-ребенок"), но если он затем оборачивается и читает снова из канала, до того, как родитель может, он будет читать свое собственное сообщение!

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню