Марк Митчелл - Программирование для Linux. Профессиональный подход
- Название:Программирование для Linux. Профессиональный подход
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:2002
- Город:Москва
- ISBN:5-8459-0243-6
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Марк Митчелл - Программирование для Linux. Профессиональный подход краткое содержание
Данная книга в основном посвящена программированию в среде GNU/Linux. Авторы применяют обучающий подход, последовательно излагая самые важные концепции и методики использования расширенных возможностей системы GNU/Linux в прикладных программах. Читатели научатся писать программы, к интерфейсу которых привыкли пользователи Linux; освоят такие технологии, как многозадачность, многопотоковое программирование, межзадачное взаимодействие и взаимодействие с аппаратными устройствами; смогут улучшить свои программы, сделав их быстрее, надежнее и безопаснее; поймут особенности системы GNU/Linux, ее ограничения, дополнительные возможности и специфические соглашения.
Книга предназначена для программистов, уже знакомых с языком С и имеющих базовый опыт работы в GNU/Linux.
Программирование для Linux. Профессиональный подход - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Вызывая функцию fork()
, программа создает свой дубликат, называемый дочерним процессом . Родительский процесс продолжает выполнять программу с той точки, где была вызвана функция fork()
. То же самое делает и дочерний процесс.
Как же различить между собой оба процесса? Во-первых, дочерний процесс — это новый, только что появившийся в системе процесс, поэтому его идентификатор отличается от идентификатора родительского процесса. Таким образом, программа может вызвать функцию getpid()
и узнать, где именно она находится. Но сама функция fork()
реализует другой способ: она возвращает разные значения в родительском и дочернем процессах. Родительский процесс получает идентификатор своего потомка, а дочернему процессу возвращается 0. В системе нет процессов с нулевым идентификатором, так что программа легко разбирается в ситуации.
В листинге 3.3 приведен пример ветвления программы с помощью функции fork()
. Учтите, что первая часть инструкции if
выполняется только в родительском процессе, тогда как ветвь else
— только в дочернем.
fork()
#include
#include
#include
int main() {
pid_t child_pid;
printf("The main program process ID is %d\n",
(int)getpid());
child_pid = fork();
if (child_pid != 0) {
printf("This is the parent process, with ID %d\n",
(int)getpid());
printf("The child's process ID is %d\n", (int)child_pid);
} else
printf("This is the child process, with ID %d\n",
(int)getpid());
return 0;
}
Функции семейства exec()
заменяют программу, выполняющуюся в текущем процессе, другой программой. Когда программа вызывает функцию exec()
, ее выполнение немедленно прекращается и начинает работу новая программа.
Функции, входящие в семейство exec()
, немного отличаются друг от друга по своим возможностям и способу вызова.
■ Функции, в названии которых присутствует суффикс 'p'
( execvp()
и execlp()
), принимают в качестве аргумента имя программы и ищут эту программу в каталогах, определяемых переменном среды PATH
. Всем остальным функциям нужно передавать полное путевое имя программы.
■ Функции, в названии которых присутствует суффикс 'v'
( execv()
, execvp()
и execve()
), принимают список аргументов программы в виде массива строковых указателей, оканчивающегося NULL
-указателем. Функции с суффиксом 'l'
( execl()
, execlp()
и execle()
) принимают список аргументов переменного размера.
■ Функции, в названии которых присутствует суффикс 'e'
( execve()
и execle()
), в качестве дополнительного аргумента принимают массив переменных среды. Этот массив содержит строковые указатели и оканчивается пустым указателем. Каждая строка должна иметь вид " ПЕРЕМЕННАЯ = значение "
.
Поскольку функция exec()
заменяет одну программу другой, она никогда не возвращает значение — только если вызов программы оказался невозможен в случае ошибки.
Список аргументов, передаваемых программе, аналогичен аргументам командной строки, указываемым при запуске программы в интерактивном режиме. Их тоже можно получить с помощью параметров argc
и argv
функции main()
. Не забывайте, когда программу запускает интерпретатор команд, первый элемент массива argv будет содержать имя программы, а далее будут находиться переданные программе аргументы. Аналогичным образом следует поступить, формируя список аргументов для функции exec()
.
Стандартная методика запуска одной программы из другой такова: сначала с помощью функции fork()
создается дочерний процесс, затем в нем вызывается функция exec()
. Это позволяет главной программе продолжать выполнение в родительском процессе.
Программа, показанная в листинге 3.4, отображает содержимое корневого каталога с помощью команды ls
, как и программа в листинге 3.2. Но на этот раз команда ls
вызывается не из интерпретатора, а напрямую; ей передаются аргументы -l
и /
.
fork()
и exec()
#include
#include
#include
#include
/* Запуск дочернего процесса в виде новой программы. Параметр
PROGRAM — это имя вызываемой программы; ее поиск будет
осуществляться в каталогах, определяемых переменной среды PATH.
Параметр ARG_LIST -- это список строковых аргументов,
передаваемых программе (должен оканчиваться указателем NULL).
Функция возвращает идентификатор порожденного процесса. */
int spawn(char* program, char** arg_list) {
pid_t child_pid;
/* Создание копии текущего процесса. */
child_pid = fork();
if (child_pid != 0)
/* Это родительский процесс. */
return child_pid;
else {
/* Выполнение указанной программы. */
execvp(program, arg_list);
/* Функция execvp() возвращает значение только в случае
ошибки. */
fprintf(stderr, "an error occurred in execvp\n");
abort();
}
}
int main() {
/* Список аргументов, передаваемых команде ls. */
char* arg_list[] = {
"ls", /* argv[0] -- имя программы. */
"-l",
NULL /* Список аргументов должен оканчиваться указателем
NULL. */
};
/* Порождаем дочерний процесс, который выполняет команду ls.
Игнорируем возвращаемый идентификатор дочернего процесса. */
spawn("ls", arg_list);
printf("done with main program\n");
return 0;
}
3.2.3. Планирование процессов
Операционная система Linux планирует работу родительских и дочерних процессов независимо друг от друга. Нет гарантии, что один процесс будет запущен раньше другого. и неизвестно, как долго один процесс будет выполняться, прежде чем Linux прервет его работу и передаст управление другому процессу. В частности, к моменту завершения родительского процесса может оказаться, что команда ls
еще не выполнена, выполнена частично или уже закончила свою работу. [11] Способ синхронизации двух процессов представлен в разделе. 3 4.1, "Ожидание завершения процесса".
Linux лишь гарантирует, что любой процесс когда-нибудь получит свой "кусочек пирога": ни один процесс не окажется полностью лишенным доступа к процессору.
Можно сообщить системе о том, что процесс не очень важен и должен выполняться с пониженным приоритетом. Это делается путем повышения фактора уступчивости процесса. По умолчанию у каждого процесса нулевой фактор уступчивости. Повышение этого значения свидетельствует о снижении приоритета процесса, и наоборот: процессы с низким (т.е. отрицательным) фактором уступчивости получают больше времени на выполнение.
Читать дальшеИнтервал:
Закладка: