2015-07-21 3 views
2

Мне нужно перенести C-программу из OpenVMS в Linux и теперь испытывать трудности с программными производными подпроцессами. Создается подпроцесс (fork отлично работает), но execve сбой (что верно, поскольку указано неправильное имя программы).C-program не возвращается из wait-statement

Но чтобы сбросить количество активных подпроцессов, я вызываю потом wait(), который не возвращается. Когда я смотрю на процесс через ps, я вижу, что больше нет подпроцессов, но wait() не возвращает ECHILD, как я думал.

while (jobs_to_be_done) 
{ 
    if (running_process_cnt < max_process_cnt) 
    { 
     if ((pid = vfork()) == 0) 
     { 
     params[0] = param1 ; 
     params[1] = NULL ; 
     if ((cstatus = execv(command, params)) == -1) 
     { 
      perror("Child - Exec failed") ; // this happens 
      exit(EXIT_FAILURE) ; 
     } 
     } 
     else if (pid < 0) 
     { 
     printf("\nMain - Child process failed") ; 
     } 
     else 
     { 
     running_process_cnt++ ; 
     } 
    } 
    else // no more free process slot, wait 
    { 
     if ((pid = wait(&cstatus)) == -1) // does not return from this statement 
     { 
     if (errno != ECHILD) 
     { 
      perror("Main: Wait failed") ; 
     } 
     anz_sub = 0 ; 
     } 
     else 
     { 
     ... 
     } 
    } 
} 

Это что-то, что нужно сделать, чтобы сообщить команде wait, что больше нет подпроцессов? С OpenVMS программа отлично работает.

спасибо заранее за вашу помощь

+0

Если (как вы говорите в комментариях к ответам), вы изменили 'vfork' на' fork' и все еще получаете проблему, я бы сказал, что, скорее всего, вы неверно истолковываете то, что происходит. Попробуйте уменьшить это до минимального, полного, компилируемого, проверяемого примера (http://stackoverflow.com/help/MCVE). – davmac

ответ

2

Я не рекомендую использовать vfork в эти дни на Linux, так как fork(2) достаточно эффективно, благодаря ленивым copy-on-write методам в ядре Linux.

Вы должны проверить результат fork. Если это не сбой, процесс был создан и wait (или waitpid(2), возможно, с WNOHANG, если вы не хотите действительно ждать, а просто узнаете о уже законченных дочерних процессах ...) не должно терпеть неудачу (даже если exec Функция у ребенка провалилась, вилка преуспела).

Вы также можете использовать , используя сигнал SIGCHLD, см. signal(7). Защитный способ использования сигналов заключается в установке некоторого флага volatile sigatomic_t в обработчиках сигналов, а также проверки и очистки этих флагов внутри вашего цикла. Напомним, что только async signal safe функции (и их довольно мало) можно назвать - даже косвенно - внутри обработчика сигналов. Читайте также о POSIX signals.

Найдите время, чтобы прочитать Advanced Linux Programming, чтобы получить более широкую картину в своем уме. Не пытайтесь имитировать OpenVMS на POSIX, но думайте в POSIX или Linux!

Возможно, вы всегда захотите, чтобы в вашей петле всегда waitpid, возможно (иногда или всегда) с WNOHANG. Так что waitpid следует вызывать не только в другой части вашего if (running_process_cnt < max_process_cnt), но, вероятно, на каждой итерации вашего цикла.

Возможно, вы захотите скомпилировать все предупреждения & отладочную информацию (gcc -Wall -Wextra -g), затем используйте отладчик gdb. Вы также можете: strace(1) свою программу (возможно, с -f)

Возможно, вам понравится memory overcommitment. Мне не нравится эта функция и обычно ее отключает (например, запустив echo 0 > /proc/sys/vm/overcommit_memory как root). См. Также proc(5), что очень полезно знать о ...

+0

Hello Basile Спасибо за ваш ответ. Я заменил vfork() на fork(), но результат все тот же. Затем я положил несколько команд сна в задание и увидел, что fork() работал нормально, execv() работает также, но после завершения подпроцессов wait() не возвращается. –

+0

Я бы сказал, что 'posix_spawn' - лучший вариант здесь, если вы можете его получить. 'fork' /' exec', к сожалению, ненадежен в общих системах, особенно 'Cygwin' и большинство (не Linux) POSIX-реализаций, не позволяющих виртуальной памяти перегружаться. (Не по теме, но я был укушен в прошлом.) – doynax

+0

Но вопрос в том, что Linux ... Когда «fork/exec» «ненадежный»? Конечно, это может потерпеть неудачу. –

1

От man vfork:

Ребенок не должен вернуться из текущей функции или вызова выхода (3), но можно назвать _exit (2)

Вы не должны называть exit(), когда вызов до execv (после vfork) не удалось - вместо этого вы должны использовать _exit(). Вполне возможно, что это само по себе вызывает проблему, которую вы видите с wait не возвращающимся.

Предлагаю вам использовать fork вместо vfork. Это намного проще и безопаснее.

Если это само по себе не решает проблему, вам нужно выполнить некоторую отладку или уменьшить код до тех пор, пока не найдете причину. Например, следующий должен работать без подвешивания:

#include <sys/wait.h> 

int main(int argc, char ** argv) 
{ 
    pid_t pid; 
    int cstatus; 
    pid = wait(&cstatus); 
    return 0; 
} 

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

+0

Здравствуйте, Я заменил операторы exit() в подпроцессе _exit() - сделал не работает ни. Затем я заменил wait() на цикл waitpid() на вызовы для реальных подпроцессов. По крайней мере, эти утверждения возвращаются, но все с возвращаемым значением 0 и errno ECHILD. Подпроцессы еще не закончены в то время, когда вызывается waitpid(). –

+0

Итак, моя проблема в том, что waitpid (pid, & cstatus, 0) возвращается, но не доставляет pid процесса завершенным или правильное состояние выхода подпроцесса. –

+0

Вырезанная версия вашего кода, которая работает для меня: http://pastebin.com/m8z0SvkH – davmac

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