Вызов system () из многопоточной программы - PullRequest
5 голосов
/ 20 декабря 2011

Мы работаем над многопоточным приложением, потребляющим память, написанным на C ++. Мы должны выполнить множество команд shellscript / linux (и получить код возврата).

Прочитав эту статью , мы ясно поняли, что было бы плохой идеей использовать system () в нашем контексте.

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

Второе решение, которое мы рассмотрели, может состоять из специального демона, написанного на python (с использованием xinetd?), Который мог бы обрабатывать наши системные вызовы.

У вас когда-нибудь была такая проблема? Как ты это решил?

Примечание: Вот более полная статья, объясняющая эту проблему: http://developers.sun.com/solaris/articles/subprocess/subprocess.html Они рекомендуют использовать posix_spawn, который использует vfork () вместо fork () (используется в system ()).

Ответы [ 3 ]

2 голосов
/ 20 декабря 2011

В статье, на которую вы ссылаетесь, в основном говорится о проблемах, если вы выполняете fork () и не сразу выполняете за ним команду exec * (). Поскольку system () обычно реализуется с помощью fork (), за которым следует exec (), большинство проблем не применимы. Одна проблема, которая действительно применима, это вопрос закрытия файловых дескрипторов; Если у вас нет особых причин поступать иначе, открытие файлов с помощью O_CLOEXEC по умолчанию, вероятно, является хорошим практическим правилом.

Одна проблема с fork () + exec () для приложений, занимающих большие объемы памяти, заключается в том, что если ваша ОС настроена так, чтобы не допускать переполнение памяти, fork () может завершиться ошибкой. Одним из решений этой проблемы является разветвление процесса «внешнего обработчика процесса» перед тем, как вы начнете выделять много памяти в вашем основном процессе.

Лучшее решение - это если требуемая функциональность доступна в виде библиотеки, избавляя от необходимости в первую очередь создавать ответвления. Это, вероятно, не согревает ваше сердце в краткосрочной перспективе, однако.

0 голосов
/ 20 декабря 2011

Как насчет этого решения:

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

Это позволит обойти проблемы с потоками при их форке перед запуском.

0 голосов
/ 20 декабря 2011

У вас будут вопросы по как вам следует вызвать внешнюю программу (fork / exec / wait, как иначе), но это только одна часть проблемы. Реальная проблема заключается в планировании этого, я полагаю, вы не хотите запускать слишком много внешних программ параллельно.

Не зная, как проходит организация потоков в вашей системе, я могу предупредить вас о двух проблемах.

Важной проблемой является сохранение нагрузки на низком уровне путем ограничения внешнего вызова команды / скрипта. Вы можете установить параметр, который сообщает, сколько параллельных внешних команд должно выполняться одновременно. Прежде чем вызывать внешнюю команду, вы должны увеличить переменную, которая показывает количество активных внешних процессов; если он превышает параметр limit, sleep () some и попробуйте снова. После завершения процесса уменьшите эту переменную. (Увеличивать и уменьшать нужно мьютексом.)

Другая проблема, когда вы используете внешнюю программу, управляете ее временем жизни. Вы должны установить «тайм-аут» для каждого внешнего процесса и уничтожить его, если он зависнет на некоторое время. Должен существовать поток «timeout» (или он должен быть основным), который управляет другими.

...