Вход/Регистрация
QNX/UNIX: Анатомия параллелизма
вернуться

Цилюрик Олег Иванович

Шрифт:

#include <sys/wait.h>

int main(void) {

int rc = system("ls");

if (rc == -1) cout << "shell could not be run" << endl;

else

cout << "result of running command is " << WEXITSTATUS(rc) << endl;

return EXIT_SUCCESS;

}

Примечание

Эта функция использует вызов

spawnlp
для загрузки новой копии командного интерпретатора, то есть «внутреннее устройство» должно быть в общем виде вам понятно. Особенностью QNX-реализации является то, что
spawnlp
всегда использует вызов
/bin/sh
, независимо от конкретного вида интерпретатора, устанавливаемого переменной окружения SHELL (ksh, bash…). Это обеспечивает независимость поведения родительского приложения от конкретных установок системы, в которой это приложение выполняется.

Вызов

system
является не только простым, но и очень наглядным, делающим код легко читаемым. Программисты часто относятся к нему с пренебрежением [10] , отмечая множество его недостатков. Однако в относительно простых случаях это может быть оптимальным решением, а недостатки не так и существенны:

• Используя копию командного интерпретатора, вызов

system
может инициировать процесс, исполняющий и бинарную программу, и скрипт на языке самого командного интерпретатора (shell), а также программный код на интерпретирующих языках, таких как Perl, Tcl/Tk и др. Многие из рассматриваемых ниже «чисто программных» способов могут загружать и исполнять только бинарный исполняемый код (по крайней мере, без использования ими весьма громоздких искусственных и альтернативных возможностей).

10

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

spawn
. При желании сделать код максимально элегантным используйте
fork
, а если ставится задача хорошей читаемости и ясности кода, то очень часто достаточно и
system
.

• Остановка родительского процесса в ожидании завершения порожденного также легко разрешается: просто запускайте дочерний процесс из отдельного потока [11] :

#include <pthread.h>

void* process(void* command) {

system((char*)command);

delete command;

return NULL;

}

int main(int argc, char *argv[]) {

11

Детали создания потока и и частности передачи ему параметра обстоятельно рассматриваются далее.

...

char* comstr = "ls -l";

pthread_create(NULL, NULL, strdup(comstr), &process);

...

}

• Часто в качестве недостатка этого способа отмечают «автономность» и невозможность взаимодействия родительского и порожденного процессов.

Но для расширения возможностей взаимосвязи процессов можно прежде всего воспользоваться вызовом

popen
(POSIX 1003.1a), являющимся в некотором роде эквивалентом, расширяющим возможности
system
. Возможности
popen
часто упускаются из виду, так как в описаниях этот вызов относится не к области создания процессов, а к области программных каналов (pipe). Синтаксис этого вызова таков:

FILE* popen(const char* command, const char* mode);

где

command
— командная строка, как и у
system
;
mode
— режим создаваемого программного канала со стороны порождающего процесса: ввод (
mode
= «r») или вывод (
mode
= «w»). Любые другие значения, указанные для
mode
, дают непредсказуемый результат.

В результате выполнения этой функции создается открытый файловый дескриптор канала (pipe), из которого породивший процесс может (

mode
= «r») читать (стандартный поток вывода дочернего процесса
STDOUT_FILENO
) или в который может (
mode
= «w») писать (стандартный поток ввода дочернего процесса
STDIN_FILENO
) стандартным образом, как это делается для типа FILE (в частности, с отработкой ситуации EOF).

Рассмотрим следующий пример. Конечно, посимвольный ввод/вывод — это не лучшее решение, и здесь мы используем его только для простоты:

int main(int argc, char** argv) {

FILE* f = popen("ls -l", "r");

if (f == NULL) perror("popen"), exit(EXIT_FAILURE);

char c;

while((с = fgetc(f)) != EOF )

cout << (islower(с) ? toupper(с) : c);

pclose(f);

return EXIT_SUCCESS;

}

Примечание

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

spawnlp(P_NOWAIT, shell_command, shell_command, "-с", command, (char*)NULL);

где

shell_command
— командный интерпретатор, специфицированный переменной окружения SHELL или утилита
/bin/sh
. В этом кроется причина возможного различия в выполнении вызовов
system
и
popen
.

Если

popen
возвращает не
NULL
, то выполнение прошло успешно. В противном случае устанавливается
errno
:
EINVAL
— недопустимый аргумент
mode
,
ENOSYS
— в системе не выполняется программа менеджера каналов. После завершения работы с каналом, созданным
popen
, он должен быть закрыт парной операцией
pclose
.

При использовании

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

  • Читать дальше
  • 1
  • ...
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: