Вход на хостинг
IT-новости
20.04.2016 iPhone 2017 года поместят в водонепроницаемый корпус из стекла
Линейка iPhone в новом году серьезно поменяется. В этом уверен аналитический исследователь Мин Чи Ку......
30.07.2015 Ищем уникальный контент для сайта
Ищем уникальный контент для сайта Без уникального контента Ваш сайт обречен на то, что его страницы......
При удачном выполнении функция не возвращает ничего (возвращать-то некому! родительский процесс уже заменён на дочерний), иначе произошла ошибка. Замечу, что в DOS, Windows и OS/2 есть ещё семейство функций spawn*, подобных exec*, но не заменяющих родительский процесс, а создающих параллельный. Причём возвращают они идентификатор процесса. Кроме этого, функции семейства spawn принимают первым параметром режим запуска, который может принимать следующие значения:
n P_WAIT – родительский процесс дожидается завершения дочернего, а затем продолжает выполнение;
n P_NOWAIT – родительский и дочерний процессы выполняются одновременно, но родительский может применить функцию wait для ожидания завершения дочернего процесса (такой режим доступен только для Win32 и OS/2);
n P_NOWAITO – идентично P_NOWAIT, но невозможен вызов wait (работает везде);
n P_DETACH – то же, что и P_NOWAITO, но дочерний процесс выполняется в фоновом режиме без доступа к клавиатуре и дисплею.
Ещё раз повторяю: функции spawn* не поддерживаются POSIX-стандартом. Для ожидания окончания дочернего процесса используется функция pid_t wait(int *process_stat). Данная функция дожидается окончания дочернего процесса и заполняет параметр process_stat. При нормальном завершении дочернего процесса старшие биты данной структуры содержат код завершения программы, иначе устанавливаются биты 1, 2, 3. Если дочерний процесс уже завершился, то функция wait немедленно возвращается, а ресурсы, занятые потомком, освобождаются. В POSIX-системах возможно также применение функции wait к нитям, но об этом далее.
Пример использования функций exec и spawn:
int main()
{
//Формирование массива аргументов
char *ar[2] = {"test.c" "-otest"};
//А теперь нашего процесса уже нет, он заменился gcc
return execvp("gcc", ar);
}
---------------------------------------------------------
int main()
{
//Запускаем gcc параллельно
spawnlp(P_NOWAIT, "gcc", "test.c", "-otest", NULL);
// Для чего-то ждём завершения gcc и выходим
return wait(NULL);
}
В POSIX определён также замечательный системный вызов fork, который выполняет «разделение» существующего процесса. После вызова fork происходит полное копирование адресного пространства существующего процесса, и далее продолжают выполняться 2 процесса, отличающихся только идентификатором процесса. Причём родителю fork возвращает идентификатор дочернего процесса, а дочернему – 0. Так можно определить тип процесса: родитель или потомок. У двух процессов после fork идентично содержимое памяти, стека, файловых дескрипторов, идентификаторов пользователя процесса (UID), каналов и т. д. Не наследуются только те участки памяти, которые были закреплены с помощью mlock(void *mem, size_t size). Можно сказать, что после вызова fork происходит разделение исходного процесса на два идентичных, но при этом между собой не связанных процесса (т.е. адресное пространство у них разное). Далее обычно дочерний и родительский процессы начинают вести себя по-разному, в зависимости от значения, возвращённого fork. C помощью fork можно выполнить множество полезных действий, например, создание демонов, сокетных серверов и т. д. Например, с помощью функции fork можно организовать поведение, аналогичное spawn в win32: