Запуск программы в C _без_ использования оболочки

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

system("command here");

Работает, конечно, но очень медленно (особенно при многократном повторении). Мне просто интересно, есть ли способ запустить программу без взаимодействия с оболочкой, что-то вроде модуль подпроцесса Python.

Я слышал о execl и буду использовать его (forkсначала, конечно), но мне интересно, есть ли более простой способ, который не требует разветвления первый.

EDIT: я также хочу знать код возврата программы


person MiJyn    schedule 30.03.2013    source источник
comment
Python, построенный на C, будет просто обертывать эту функциональность. Все, что вам нужно сделать, это определить свою собственную функцию для разветвления и выполнения, а затем использовать ее везде, где вам это нужно.   -  person Dave    schedule 30.03.2013
comment
@ Дэйв, да, конечно, но как мне узнать код возврата программы?   -  person MiJyn    schedule 30.03.2013
comment
Вы можете waitpidWNOHANG, если вы хотите быть асинхронным), что даст вам статус выхода после его закрытия.   -  person Dave    schedule 30.03.2013
comment
@ Дэйв, спасибо, я попробую это! :D   -  person MiJyn    schedule 30.03.2013
comment
(и, чтобы было ясно, pid — это то, что вы получаете от fork, если вы находитесь в основной программе. И вы получаете 0, если вы находитесь в дочерней программе)   -  person Dave    schedule 30.03.2013
comment
Вы не сказали, какая у вас ОС, но вы могли бы использовать spawn: linux.die .net/man/3/posix_spawnp   -  person Gabe    schedule 30.03.2013
comment
@ Гейб, хм, интересно... но это действительно выглядит не слишком красиво (я думаю, что fork/execl было бы легче читать)...   -  person MiJyn    schedule 30.03.2013


Ответы (2)


Если ни system(), ни popen() предоставляет необходимый вам механизм, а простой способ сделать это с помощью fork() и execv() (или, возможно, execl(), но для его использования список аргументов должен быть фиксированным во время компиляции, а не переменным). Действительно! Нетрудно выполнить fork() и exec(), и любая альтернатива инкапсулирует эту обработку.

Модуль подпроцесса Python просто скрывает fork() и exec() за удобным интерфейсом. Вероятно, это подходит для языка высокого уровня, такого как Python. C — это язык более низкого уровня, и ему не нужна сложность.

Сложный способ сделать это — использовать posix_spawn(). Вы должны создать аргументы для описания всех действий, которые вы хотите выполнить в дочернем элементе между fork() и exec(), что гораздо сложнее настроить, чем просто выполнить fork(), внести изменения, а затем использовать exec() в конце концов. Это (posix_spawn()) — это то, что вы получаете, когда разрабатываете код для порождения дочернего процесса без явного использования fork() и exec() и гарантируете, что он может обрабатывать практически любые разумные обстоятельства.

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

person Jonathan Leffler    schedule 30.03.2013

Я уверен, вы уже знаете, что system уже использует стратегию fork/exec. Я понимаю, что вы хотите обойти оболочку и ищете простой подход, я просто говорю, что вы могли бы так же легко написать функцию для переноса шаблона fork/exec, как это делается в system. На самом деле, было бы, наверное, проще всего просто сделать это. Альтернативой, упомянутой Гейбом в комментариях, является posix_spawn.

Более быстрая (но явно обескураживающая) альтернатива — vfork() / exec, но это обычно не рекомендуется и устарело в последних стандартах POSIX.

4.3BSD; POSIX.1-2001 (но помечен как УСТАРЕВШИЙ). POSIX.1-2008 удаляет спецификацию vfork().

Это должно быть сразу, за которым следует exec или _exit. В противном случае могут возникнуть всевозможные странные ошибки, поскольку страницы виртуальной памяти и таблицы страниц не дублируются (потомок использует одни и те же сегменты данных/кучи/стека). Родительский/вызывающий процесс блокируется до тех пор, пока дочерний процесс не достигнет execs или _exits. Современные реализации обычного fork имеют семантику копирования при записи, которая приближается по скорости к vfork, без потенциальных ошибок, возникающих из-за семантики совместного использования памяти vfork.

Если вам нужен еще дальнейший контроль над семантикой совместного использования памяти и наследования процессов, а также последующее потенциальное ускорение (и в Linux), загляните на clone() (оболочка для системного вызова sys_clone()), которому некоторые системные вызовы, создающие процессы, делегируют свою работу. Не забудьте тщательно прочесать все различные флаги.

Вы можете использовать waitpid, чтобы получить статус завершения процесса.

person Jorge Israel Peña    schedule 30.03.2013
comment
vfork() странно; правила аккуратного использования очень строгие; легко ошибиться. - person Jonathan Leffler; 30.03.2013
comment
@JonathanLeffler Действительно. Надеюсь, я достаточно ясно объяснил это ОП, чтобы они могли более тщательно взвесить свои варианты. - person Jorge Israel Peña; 30.03.2013