Марк Митчелл - Программирование для Linux. Профессиональный подход

Скачивание начинается... Если скачивание не началось автоматически, пожалуйста нажмите на эту ссылку.
Жалоба
Напишите нам, и мы в срочном порядке примем меры.
Описание книги "Программирование для Linux. Профессиональный подход"
Описание и краткое содержание "Программирование для Linux. Профессиональный подход" читать бесплатно онлайн.
Данная книга в основном посвящена программированию в среде GNU/Linux. Авторы применяют обучающий подход, последовательно излагая самые важные концепции и методики использования расширенных возможностей системы GNU/Linux в прикладных программах. Читатели научатся писать программы, к интерфейсу которых привыкли пользователи Linux; освоят такие технологии, как многозадачность, многопотоковое программирование, межзадачное взаимодействие и взаимодействие с аппаратными устройствами; смогут улучшить свои программы, сделав их быстрее, надежнее и безопаснее; поймут особенности системы GNU/Linux, ее ограничения, дополнительные возможности и специфические соглашения.
Книга предназначена для программистов, уже знакомых с языком С и имеющих базовый опыт работы в GNU/Linux.
Опытные программисты часто создают несколько взаимодействующих процессов в рамках одного приложения, чтобы оно могло выполнять группу действий одновременно. Это повышает надежность приложения и позволяет ему использовать уже написанные программы.
Большинство описанных в данной главе функций управления процессами доступно и в других UNIX-системах. В основном они объявлены в файле <unistd.h>, но не помешает проверить это в документации.
3.1. Знакомство с процессами
Пользователю достаточно войти в систему, чтобы в ней начали выполняться процессы. Даже если пользователь ничего не запускает, а просто сидит перед экраном и пьет кофе. в системе все равно "теплится жизнь". Любой выполняющейся программе соответствует один или несколько процессов. Давайте для начала познакомимся с теми из них, которые присутствуют по умолчанию.
3.1.1. Идентификаторы процессов
Каждый процесс в Linux помечается уникальным идентификатором (PID, process identifier). Идентификаторы — это 16-разрядные числа, назначаемые последовательно по мере создания процессов.
У всякого процесса имеется также родительский процесс (за исключением специального демона init, о котором рассказывается в разделе 3.4.3, "Процессы-зомби"). Таким образом, все процессы Linux организованы в виде древовидной иерархии, на вершине которой находится процесс init. К атрибутам процесса относится идентификатор его предка (PPID, parent process identifier).
Работая с идентификаторами процессов в программах, написанных на языках С и C++, следует объявлять соответствующие переменные как имеющие тип pid_t (определен в файле <sys/types.h>). Программа может узнать идентификатор своего собственного процесса с помощью системного вызова getpid(), а идентификатор своего родительского процесса — с помощью вызова getppid(). В листинге 3.1 показано, как это сделать.
Листинг 3.1. (print-pid.c) Вывод идентификатора процесса#include <stdio.h>
#include <unistd.h>
int main() {
printf("The process ID is %d\n", (int)getpid());
printf("The parent process ID is %d\n", (int)getppid());
return 0;
}
Обратите внимание на важную особенность: при каждом вызове программа сообщает о разных идентификаторах, поскольку всякий раз запускается новый процесс. Тем не менее, если программа вызывается из одного и того же интерпретатора команд, то родительский идентификатор оказывается одинаковым.
3.1.2. Получение списка активных процессов
Команда ps отображает список процессов, работающих в данный момент в системе. Версия этой команды в GNU/Linux имеет множество опций, так как пытается быть совместимой со своими "родственниками" в других UNIX-системах. С помощью опций можно указывать, о каких процессах и какую именно требуется получить информацию.
Будучи вызванной без аргументов, команда ps выводит список тех процессов, управляющим терминалом которых является ее собственный терминал:
% ps
PID TTY TIME CMD
21693 pts/8 00:00:00 bash
21694 pts/8 00:00:00 ps
В данном случае мы видим два процесса. Первый из них. bash, — это интерпретатор команд, запущенный на данном терминале. Второй — выполняющийся экземпляр самой команды ps. В самом левом столбце, PID, отображаются идентификаторы процессов.
Более полный список можно получить с помощью следующей команды:
% ps -е -о pid,ppid,command
Опция -е заставляет команду ps отображать все процессы, выполняющиеся в системе. Опция -о pid,ppid,command сообщает о том, какая информация о процессе нас интересует. В данном случае это идентификатор самого процесса, идентификатор его родительского процесса и команда, посредством которой был запущен процесс.
Форматы вывода команды psВ опции -o через запятую указываются столбцы которые должны быть включены в вывод команды ps. Например, команда ps -о pid,user,start_time,command отображает идентификатор процесса, имя его владельца, время запуска а также команду, соответствующую процессу. Полный список опций и столбцов можно узнать на man-странице команды ps. Имеются три предопределенных формата вывода: -f (полный листинг), -l (длинный листинг) и -j (вывод заданий)
Ниже приведено несколько первых и последних строк, выдаваемых этой командой в нашей системе:
% ps -e -о pid,ppid,command
PID PPID COMMAND
1 0 init [5]
2 1 [kflushd]
3 1 [kupdate]
...
21725 21693 xterm
21727 21725 bash
21728 21727 ps -e -o pid,ppid,command
Заметьте: родительский идентификатор команды ps, 21727, соответствует интерпретатору bash, из которого была вызвана команда. В свою очередь, родительский идентификатор интерпретатора, 21725, принадлежит программе xterm — эмулятору терминала, в котором выполняется интерпретатор.
3.1.3. Уничтожение процесса
Для уничтожения процесса предназначена команда kill. Ей достаточно указать идентификатор требуемого процесса.
Команда kill посылает процессу сигнал SIGTERM, являющийся запросом на завершение.[10] По умолчанию, если в программе отсутствует обработчик данного сигнала, процесс просто завершает свою работу. О сигналах речь пойдет в разделе 3.3, "Сигналы".
3.2. Создание процессов
Существуют два способа создания процессов. Первый из них относительно прост, но применяется редко, поскольку неэффективен и связан со значительным риском для безопасности системы. Второй способ сложнее, но избавлен от недостатков первого.
3.2.1. Функция system()
Функция system() определена в стандартной библиотеке языка С и позволяет вызывать из программы системную команду, как если бы она была набрана в командной строке. По сути, эта функция запускает стандартный интерпретатор Bourne shell (/bin/sh) и передает ему команду на выполнение. Например, программа, представленная в листинге 3.2, вызывает команду ls -l /, отображающую содержимое корневого каталога.
Листинг 3.2. (system.c) Использование функции system()#include <stdlib.h>
int main() {
int return_value;
return_value = system("ls -l /");
return return_value;
}
Функция system() возвращает код завершения указанной команды. Если интерпретатор не может быть запущен, возвращается значение 127, а в случае возникновения других ошибок — -1.
Поскольку функция system() запускает интерпретатор команд, она подвержена всем тем ограничениям безопасности, что и системный интерпретатор. Рассчитывать на наличие какой-то конкретной версии Bourne shell не приходится. В большинстве UNIX-систем программа /bin/sh представляет собой символическую ссылку на другой интерпретатор. В Linux — это bash (Bourne-Again SHell), причем в разных дистрибутивах присутствуют разные его версии. Вызов из функции system() программы с привилегиями пользователя root также может иметь неодинаковые последствия в разных системах. Таким образом, лучше создавать процессы с помощью функций fork() и exec().
3.2.2. Функции fork() и exec()
В DOS и Windows API имеется семейство функций spawn(). Они принимают в качестве аргумента имя программы, создают новый экземпляр ее процесса и запускают его. В Linux нет функции, которая делала бы все это за один заход. Вместо этого имеется функция fork(), создающая дочерний процесс, который является точной копией родительского процесса, и семейство функций exec(), заставляющих требуемый процесс перестать быть экземпляром одной программы и превратиться в экземпляр другой программы. Чтобы создать новый процесс, нужно сначала с помощью функции fork() создать копню текущего процесса, а затем с помощью функции exec() преобразовать одну из копий в экземпляр запускаемой программы.
Вызов функции fork()Вызывая функцию fork(), программа создает свой дубликат, называемый дочерним процессом. Родительский процесс продолжает выполнять программу с той точки, где была вызвана функция fork(). То же самое делает и дочерний процесс.
Как же различить между собой оба процесса? Во-первых, дочерний процесс — это новый, только что появившийся в системе процесс, поэтому его идентификатор отличается от идентификатора родительского процесса. Таким образом, программа может вызвать функцию getpid() и узнать, где именно она находится. Но сама функция fork() реализует другой способ: она возвращает разные значения в родительском и дочернем процессах. Родительский процесс получает идентификатор своего потомка, а дочернему процессу возвращается 0. В системе нет процессов с нулевым идентификатором, так что программа легко разбирается в ситуации.
Подписывайтесь на наши страницы в социальных сетях.
Будьте в курсе последних книжных новинок, комментируйте, обсуждайте. Мы ждём Вас!
Похожие книги на "Программирование для Linux. Профессиональный подход"
Книги похожие на "Программирование для Linux. Профессиональный подход" читать онлайн или скачать бесплатно полные версии.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.
Отзывы о "Марк Митчелл - Программирование для Linux. Профессиональный подход"
Отзывы читателей о книге "Программирование для Linux. Профессиональный подход", комментарии и мнения людей о произведении.