2016-09-26 5 views
-1

Я перенаправляет вывод из дочернего процесса:Перенаправление вывода дочернего процесса

int pipefd[2]; 
pipe(pipefd); 
pid_t pid = fork(); /* Create a child process */ 

switch (pid) { 
case -1: /* Error */ 
    cout << "Uh-Oh! fork() failed.\n"; 
    exit(1); 
case 0: /* Child process */ 
    close(pipefd[0]); 
    dup2(pipefd[1], 1); 
    dup2(pipefd[1], 2); 
    close(pipefd[1]); 
    execv(args[0], (char * const *)args); 
    cout << "execv() error" << endl; 
    exit(1); 
default: /* Parent process */ 
    close(pipefd[1]); 
    char buffer[1024]; 
    size_t bytes_read = 0; 
    bytes_read = read(pipefd[0], buffer, sizeof(buffer)); 
    if(bytes_read == -1) { 
     cout << "read() error" << endl; 
     exit(1); 
    } 

    close(pipefd[0]); 

    if(bytes_read > 0) { 
     buffer[bytes_read-1] = '\0'; // Overwrite the newline 
    } 

    int status, exit_pid; 
    while(true) { 
     exit_pid = waitpid(pid, &status, 0); 
     if(exit_pid == -1) { 
      cout << "waitpid() error: " << strerror(errno) << endl; 
      exit(1); 
     } 
     else { 
      return WEXITSTATUS(status); 
     } 
    } 
} 

Это прекрасно работает, когда я запустил его как изолированный кусок кода. Но когда я интегрирую его в свою многопоточную среду, происходит ужасная вещь: вызовы read() как-то читают вывод других потоков родительского процесса, как если бы это был выход из канала дочернего процесса. Кто-нибудь сталкивался с такой вещью? Я на OS X.

+0

Использовать ли другие потоки stdout и stderr для вывода вывода? Тогда это поведение абсолютно нормальное и ожидаемое. –

+0

Да, да, но я не понимаю, почему это должно вызывать такое поведение. Вызов pipe() выделяет новые файловые дескрипторы, а dup2() в дочернем случае не влияет на таблицу родительских дескрипторов. – Yuval

+0

Вы знаете, что ['dup2 (pipefd [1], 1);'] (http://man7.org/linux/man-pages/man2/dup.2.html) на самом деле, не так ли? –

ответ

0

Ну, у меня есть решение, хотя я не совсем понимаю, почему это произошло.

Но сначала должно быть ясно, что это поведение не является ни нормальным, ни ожидаемым. Детский процесс, созданный с помощью fork(), не наследует ни одного работающего потока от его родителя (поэтому неожиданный вывод должен поступать из родительских потоков). И у него есть своя таблица дескрипторов. Поэтому, когда дочерний процесс вызывает dup2(), чтобы изменить свои дескрипторы вывода, это не должно влиять на потоки в родительском процессе.

Проблема возникла только в тех случаях, когда вызов execv() не удался. В этих случаях я ожидал завершения дочернего процесса, чтобы закрыть все его файловые дескрипторы. Но этого не произошло, или, по крайней мере, это не имело такого же эффекта, как вызов close() явно. Поэтому добавление явного закрытия() вызывает после execv() решена проблема:

execv(args[0], (char * const *)args); 
close(1); 
close(2); 
exit(1); 

Тесное от записи конечного дескриптора трубы, что приведет к операции чтения на чтение-конца, чтобы получить 0, таким образом, зная, что больше не читаю. Однако, я до сих пор не знаю следующее:

  1. Почему не вызов выхода() в дочернем процессе, эквивалентном явного вызова близко()?
  2. Даже если конец записи в трубе не закрыт, почему чтение с чтения-вывода вызывает вывод потоков в родительском процессе вместо блокировки или возврата некоторой ошибки?

Если кто-то может пролить свет на это, он будет оценен.

Смежные вопросы