QNX/UNIX: Анатомия параллелизма - Цилюрик Олег Иванович Страница 7

Тут можно читать бесплатно QNX/UNIX: Анатомия параллелизма - Цилюрик Олег Иванович. Жанр: Компьютеры и Интернет / Интернет. Так же Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте Knigogid (Книгогид) или прочесть краткое содержание, предисловие (аннотацию), описание и ознакомиться с отзывами (комментариями) о произведении.

QNX/UNIX: Анатомия параллелизма - Цилюрик Олег Иванович читать онлайн бесплатно

QNX/UNIX: Анатомия параллелизма - Цилюрик Олег Иванович - читать книгу онлайн бесплатно, автор Цилюрик Олег Иванович

Создание нового процесса

Созданию процессов (имеется в виду создание процесса из программного кода) посвящено столько описаний [1-9], что детальное рассмотрение этого вопроса было бы лишь пересказом. Поэтому мы ограничимся только беглым перечислением этих возможностей, тем более что в ходе обсуждения нас главным образом интересуют не сами процессы, а потоки, заключенные в адресных пространствах процессов.

Использование командного интерпретатора

Самый простой способ — запустить из программного кода дочернюю копию командного интерпретатора, которому затем передать команду запуска процесса. Для этого используется вызов:

int system(const char* command);

где command— текстовая строка, содержащая команду, которую предполагается выполнить ровно в том виде, в котором мы вводим ее командному интерпретатору с консоли.

Примечание

Функция имеет еще одну специфическую форму вызова, когда в качестве commandзадается NULL. По коду возврата это позволяет выяснить, присутствует ли (и доступен ли) командный интерпретатор в системе (возвращается 0, если интерпретатор доступен).

На время выполнения вызова system()вызывающий процесс приостанавливается. После завершения порожденного процесса функция возвращает код завершения вновь созданной копии интерпретатора (или -1, если сам интерпретатор не может быть выполнен), то есть младшие 8 бит возвращаемого значения содержат код завершения выполняемого процесса. Возврат вызова system()может анализироваться макросом WEXITSTATUS(), определенным в файле <sys/wait.h>. Например:

#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 и др. Многие из рассматриваемых ниже «чисто программных» способов могут загружать и исполнять только бинарный исполняемый код (по крайней мере, без использования ими весьма громоздких искусственных и альтернативных возможностей).

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

#include <pthread.h>

void* process(void* command) {

 system((char*)command);

 delete command;

 return NULL;

}

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

 ...

 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 )

Перейти на страницу:
Вы автор?
Жалоба
Все книги на сайте размещаются его пользователями. Приносим свои глубочайшие извинения, если Ваша книга была опубликована без Вашего на то согласия.
Напишите нам, и мы в срочном порядке примем меры.
Комментарии / Отзывы
    Ничего не найдено.