Категории
Самые читаемые
PochitayKnigi » Компьютеры и Интернет » Программное обеспечение » Linux программирование в примерах - Арнольд Роббинс

Linux программирование в примерах - Арнольд Роббинс

Читать онлайн Linux программирование в примерах - Арнольд Роббинс

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 67 68 69 70 71 72 73 74 75 ... 165
Перейти на страницу:

9.1.1.3. Разделение дескрипторов файлов и close()

Тот факт, что несколько дескрипторов файлов могут указывать на один и тот же открытый файл, имеет важное следствие: файл не закрывается до тех пор, пока не будут закрыты все дескрипторы файла.

Позже в главе мы увидим, что несколько дескрипторов для одного файла могут существовать не только для разных процессов, но даже и внутри одного и того же процесса; это правило особенно важно для работы с каналами (pipes).

Если вам нужно узнать, открыты ли два дескриптора для одного и того же файла, можете использовать fstat() (см. раздел 5.4.2 «Получение сведений о файле») для двух дескрипторов с двумя различными структурами struct stat. Если соответствующие поля st_dev и st_ino равны, это один и тот же файл.

Позже в главе мы завершим обсуждение манипуляций с дескрипторами файлов и таблицей дескрипторов файлов.

9.1.2. Идентификация процесса: getpid() и getppid()

У каждого процесса есть уникальный ID номер процесса (PID). Два системных вызова предоставляют текущий PID и PID родительского процесса:

#include <sys/types.h> /* POSIX */

#include <unistd.h>

pid_t getpid(void);

pid_t getppid(void);

Функции так просты, как выглядят:

pid_t getpid(void) Возвращает PID текущего процесса

pid_t getppid(void)Возвращает PID родителя.

Значения PID уникальны; по определению, не может быть двух запущенных процессов с одним и тем же PID. PID обычно возрастают в значении, так что порожденный процесс имеет обычно больший PID, чем его родитель. Однако, на многих системах значения PID переполняются; когда достигается значение системного максимума для PID, следующий процесс создается с наименьшим не используемым номером PID. (Ничто в POSIX не требует такого поведения, и некоторые системы назначают неиспользуемые номера PID случайным образом.)

Если родительский процесс завершается, порожденный получает нового родителя, init. В этом случае PID родителя будет 1, что является PID init. Такой порожденный процесс называется висячим (orphan). Следующая программа, ch09-reparent.с, демонстрирует это. Это также первый пример fork() в действии:

1  /* ch09-reparent.c --- показывает, что getppid() может менять значения */

2

3  #include <stdio.h>

4  #include <errno.h>

5  #include <sys/types.h>

6  #include <unistd.h>

7

8  /* main --- осуществляет работу */

9

10 int main(int argc, char **argv)

11 {

12  pid_t pid, old_ppid, new_ppid;

13  pid_t child, parent;

14

15  parent = getpid(); /* перед fork() */

16

17  if ((child = fork()) < 0) {

18   fprintf(stderr, "%s: fork of child failed: %sn",

19    argv[0], strerror(errno));

20   exit(1);

21  } else if (child == 0) {

22   old_ppid = getppid();

23   sleep(2); /* см. главу 10 */

24   new_ppid = getppid();

25  } else {

26   sleep(1);

27   exit(0); /* родитель завершается после fork() */

28  }

29

30  /* это выполняет только порожденный процесс */

31  printf("Original parent: %dn", parent);

32  printf("Child: %dn", getpid());

33  printf("Child's old ppid: %dn", old_ppid);

34  printf("Child's new ppid: %dn", new_ppid);

35

36  exit(0);

37 }

Строка 15 получает PID начального процесса, используя getpid(). Строки 17–20 создают порожденный процесс, проверяя по возвращении ошибки.

Строки 21–24 выполняются порожденным процессом: строка 22 получает PPID. Строка 23 приостанавливает процесс на две секунды (сведения о sleep() см в разделе 10.8.1 «Аварийные часы: sleep(), alarm() и SIGALRM»), а строка 24 снова получает PPID.

Строки 25–27 исполняются в родительском процессе. Строка 26 задерживает родителя на одну секунду, давая порожденному процессу достаточно времени для осуществления первого вызова getppid(). Строка 27 завершает родителя.

Строки 31–34 выводят значения. Обратите внимание, что переменная parent, которая была установлена до разветвления, сохраняет свое значение в порожденном процессе. После порождения у двух процессов идентичные, но независимые копии адресного пространства. Вот что происходит при запуске программы:

$ ch09-reparent /* Запуск программы */

$ Original parent: 6582 /* Программа завершается: приглашение оболочки

                           и вывод порожденного процесса */

Child: 6583

Child's old ppid: 6582

Child's new ppid: 1

Помните, что обе программы выполняются параллельно. Графически это изображено на рис. 9.2.

Рис. 9.2. Два параллельно исполняющихся процесса после разветвления

ЗАМЕЧАНИЕ. Использование sleep(), чтобы заставить один процесс пережить другой, работает в большинстве случаев. Однако, иногда случаются ошибки, которые трудно воспроизвести и трудно обнаружить. Единственным способом гарантировать правильное поведение является явная синхронизация с помощью wait() или waitpid(), которые описываются далее в главе (см. раздел 9.1.6.1 «Использование функций POSIX: wait() и waitpid()»).

9.1.3. Установка приоритетов процесса: nice()

Когда процессы запущены, ядро динамически меняет приоритет каждого процесса. Как и в жизни, элементы с большим приоритетом получают внимание до элементов с меньшим приоритетом. Короче говоря, каждому процессу выделяется небольшая порция времени для исполнения, которая называется квантом времени (time slice). Когда квант истекает, если текущий процесс все еще является процессом с наивысшим приоритетом, ему разрешается продолжать.

Linux, как и Unix, обеспечивает вытесняющую многозадачность. Это означает, что ядро может вытеснить процесс (приостановить его), если настало время дать возможность поработать другому процессу. Приоритет длительное время работающих процессов (например, процессов, выполняющих интенсивные вычисления), снижается в конце их кванта времени, поэтому они дают шанс другим процессам получить время процессора. Сходным образом, процессам, длительное время бездействовавшим в ожидании завершения ввода/вывода (таким, как интерактивный текстовый редактор), приоритет повышается, так что они могут ответить на ввод/вывод, когда он происходит. Короче, ядро гарантирует, что все процессы, усредненные по времени, получают свою «справедливую долю» времени процессора. Повышение и понижение приоритетов является частью этого процесса.

Проектирование хорошего планировщика процессов для ядра является искусством; практические подробности выходят за рамки данной книги. Однако, процесс может влиять на назначения приоритетов ядром посредством своего значения относительного приоритета (nice).

Значение относительного приоритета является указанием того, насколько «приятным» хочет быть процесс в отношении других процессов. В соответствии с этим большие значения означают во все большей степени терпеливые процессы; т.е. те, которые все более приятны другим, снижая свой приоритет по отношению к ним.

Отрицательное значение относительного приоритета, с другой стороны, означает, что процесс желает быть «менее приятным» по отношению к другим. Такой процесс более эгоистичный, требуя себе большего количества времени процессора[89]. К счастью, в то время как пользователи могут повышать значение относительного приоритета (быть более приятными), лишь root может снижать значение относительного приоритета (быть менее приятным).

Значение относительного приоритета является лишь одним фактором в уравнении, используемом ядром для вычисления приоритета; это не значение самого приоритета, которое изменяется с течением времени на основе поведения процесса и состояния других процессов системы. Для изменения значения относительного приоритета используется системный вызов nice():

#include <unistd.h> /* XSI */

int nice(int inc);

Значение относительного приоритета по умолчанию равно 0. Разрешен диапазон значений от -20 до 19. Это требует некоторой привычки. Чем более отрицательное значение, тем выше приоритет процесса: -20 является наивысшим приоритетом (наименьшая приятность), а 19 — наинизшим приоритетом (наибольшая приятность)

Аргумент inc является приращением, на который надо изменить значение приоритета. Для получения текущего значения, не изменяя его, используйте 'nice(0)'. Если результат 'текущий_относительный_приоритет + inc' выйдет за пределы от -20 до 19, система принудительно включит его в этот диапазон.

1 ... 67 68 69 70 71 72 73 74 75 ... 165
Перейти на страницу:
Тут вы можете бесплатно читать книгу Linux программирование в примерах - Арнольд Роббинс.
Комментарии