Обе функции, dlopen()
dlsym()
, в случае неудачного завершения возвращают NULL
. В данной ситуации можно вызвать функцию dlerror()
(без параметров), чтобы получить текстовое описание возникшей ошибки.Функция dlclose()
dlopen()
загружает библиотеку лишь в том случае, если она еще не находится в памяти. В противном случае просто увеличивается число ссылок на файл. Аналогичным образом функция dlclose()
сначала уменьшает счетчик ссылок, и только если он становится равным нулю, выгружает библиотеку.Когда совместно используемая библиотека пишется на C++, имеет смысл объявлять общедоступные функции со спецификатором extern "С"
my_function()
написана на C++ и находится в совместно используемой библиотеке, а нужно обеспечить доступ к ней с помощью функции dlsym()
, объявите ее следующим образом:extern "С" void my_function();
Тем самым компилятору C++ будет запрещено подменять имя функции. При отсутствии спецификатора extern "С"
my_function
совершенно другое имя, в котором закодирована информация о данной функции. Компилятор языка С не заменяет имена; он работает с теми именами, которые назначены пользователем.Глава 3
Процессы
Выполняющийся экземпляр программы называется
Опытные программисты часто создают несколько взаимодействующих процессов в рамках одного приложения, чтобы оно могло выполнять группу действий одновременно. Это повышает надежность приложения и позволяет ему использовать уже написанные программы.
Большинство описанных в данной главе функций управления процессами доступно и в других UNIX-системах. В основном они объявлены в файле
3.1. Знакомство с процессами
Пользователю достаточно войти в систему, чтобы в ней начали выполняться процессы. Даже если пользователь ничего не запускает, а просто сидит перед экраном и пьет кофе. в системе все равно "теплится жизнь". Любой выполняющейся программе соответствует один или несколько процессов. Давайте для начала познакомимся с теми из них, которые присутствуют по умолчанию.
3.1.1. Идентификаторы процессов
Каждый процесс в Linux помечается уникальным идентификатором (PID, process identifier). Идентификаторы — это 16-разрядные числа, назначаемые последовательно по мере создания процессов.
У всякого процесса имеется также родительский процесс (за исключением специального демона init
init
. К атрибутам процесса относится идентификатор его предка (PPID, parent process identifier).Работая с идентификаторами процессов в программах, написанных на языках С и C++, следует объявлять соответствующие переменные как имеющие тип pid_t
). Программа может узнать идентификатор своего собственного процесса с помощью системного вызова getpid()
, а идентификатор своего родительского процесса — с помощью вызова getppid()
. В листинге 3.1 показано, как это сделать.#include
#include
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
Будучи вызванной без аргументов, команда ps выводит список тех процессов, управляющим терминалом которых является ее собственный терминал:
% ps
PID TTY TIME CMD