2014-11-14 3 views
2

Я пытаюсь понять, как правильно использовать fork() и execvp() для выполнения команды. До сих пор у меня есть следующий код:Как правильно fork() процесс

Когда я запустил ./test vim myFile.c, он правильно открыл myFile.c, но я получаю странное поведение. Кажется, что есть два процесса, потому что всякий раз, когда я вводил что-либо, похоже, это происходит дважды. Почему это?

int main (int argc, char* argv[]) { 
    int fdin, pid, w, status; 
    fdin = 0;                 
    if ((pid = fork()) < 0)              
     errorExit (EXIT_FAILURE);                                
    execvp(argv[0],argv); 

    do { 
     w = waitpid(cpid, &status, WUNTRACED | WCONTINUED); 
     if (w == -1) { 
      perror("waitpid"); 
      exit(EXIT_FAILURE); 
     } 

    if (WIFEXITED(status)) { 
      printf("exited, status=%d\n", WEXITSTATUS(status)); 
     } else if (WIFSIGNALED(status)) { 
      printf("killed by signal %d\n", WTERMSIG(status)); 
     } else if (WIFSTOPPED(status)) { 
      printf("stopped by signal %d\n", WSTOPSIG(status)); 
     } else if (WIFCONTINUED(status)) { 
      printf("continued\n"); 
     } 
    } while (!WIFEXITED(status) && !WIFSIGNALED(status)) 
} 
+0

'execvp (argv [0], argv)' должен просто продолжать выполнение одной и той же программы ('test', а не' vim'!) Снова и снова, поскольку вы вызываете ее как для родителя, так и для дочернего элемента 'fork() '... – vanza

+0

после fork() код должен различать родительский и дочерний. Ваш код не делает различий, поэтому и родительский, и дочерний будут работать с кодом. Таким образом, родительский и дочерний функции выполняет функцию execvp(). чтобы дифференцировать, проверьте возвращаемое значение pid, если == 0, а затем в child, иначе в родительском. родительский (pid not - 0) пропустить вызов execvp – user3629249

ответ

3

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

Следовательно, предполагая, что fork преуспел, fork вернет неотрицательное целое число как родительскому, так и дочернему процессу в строке 4. Затем как родительский, так и дочерний процесс будут выполнять строку 6, execvp, и, следовательно, вы получите два разных процесса, запускающих ваш vim myFile.c, вызывая все описанные вами проблемы.

Стандартная идиома что-то вроде:

if ((pid = fork()) < 0) { 
    // Handle fork error 
} 
else if (pid == 0) { 
    // Child process 
    execvp(...); 
} 
else { 
    // Parent process 
    w = waitpid(pid, ...); 
} 

Поскольку возвращаемое значение для вилки 0 для ребенка, после того, как вилка успешно, тест (PID == 0) будет верно для ребенка, так execvp будет вызван.

Для родителя fork возвращает pid дочернего элемента, поэтому проверка (pid == 0), которая все еще выполняется, является ложной, поэтому выполняется условие else, заставляя родителя ждать дочернего элемента.

+0

Нужно ли делать цикл while? – Apollo

+0

Нет, вам не нужен цикл while. По умолчанию waitpid заставит родителя спать до тех пор, пока ребенок не выйдет. Например, см. Http://linux.die.net/man/2/waitpid. –

+0

, если вы перейдете к нижней части страницы руководства, вы увидите, что их примерный код включает цикл while. Почему это? – Apollo

3

Оба родителя и ребенок в вашей программе получить execvp():

if ((pid = fork()) < 0) 
    errorExit (EXIT_FAILURE); 
execvp(argv[0],argv); 

Вы должны проверить, если вы находитесь в родителе с pid != 0, и если вы в детстве в противном случае.

+0

Нужно ли мне цикл while? – Apollo

0

Вы должны посмотреть на возвращаемое значение fork, после успешной вилки у вас будет две запущенные процессы в том же положении в вашей программе. Детский процесс получит возвращаемое значение 0, родитель получит возвращаемое значение, которое является pid для дочернего элемента. Скорее всего, вы хотите делать разные вещи в дочернем процессе и родительском процессе.

Возможно, вам также захочется подумать о том, как вызывается execvp. Вы действительно хотите дать «./test» в качестве первого аргумента execvp?

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