Книга: Основы программирования в Linux
Ресурсы и ограничения
Разделы на этой странице:
Ресурсы и ограничения
Программы, выполняющиеся в системе Linux, зависят от ограниченности ресурсов. Это могут быть физические ограничения, накладываемые оборудованием (например, памятью), ограничения, связанные с системной политикой (например, разрешенное время процессора) или ограничения реализации (такие как размер типа integer
или максимально допустимое количество символов в имени файла). В спецификацию UNIX включены некоторые из этих ограничений, которые может определять приложение. Дальнейшее обсуждение ограничений и последствия их нарушений см. в главе 7.
В заголовочном файле limits.h определены многие именованные константы, представляющие ограничения, налагаемые операционной системой (табл. 4.8).
Таблица 4.8
Ограничительная константа | Назначение |
---|---|
NAME_MAX |
Максимальное число символов в имени файла |
CHAR_BIT |
Количество разрядов в значении типа char |
CHAR_MAX |
Максимальное значение типа char |
INT_MAX |
Максимальное значение типа int |
Существует множество других ограничений, полезных приложению, поэтому следует ознакомиться с заголовочными файлами установленной у вас версии системы.
Примечание
Имейте в виду, что константа NAME_MAX
зависит от файловой системы. Для разработки легко переносимого кода следует применять функцию pathconf. Дополнительную информацию о ней см. на страницах интерактивного справочного руководства.
В заголовочном файле sys/resource.h представлены определения операций над ресурсами. К ним относятся функции для считывания и установки предельных значений для разрешенного размера программы, приоритета выполнения и файловых ресурсов.
#include <sys/resource.h>
int getpriority(int which, id_t who);
int setpriority(int which, id_t who, int priority);
int getrlimit(int resource, struct rlimit *r_limit);
int setrlimit(int resource, const struct rlimit *r_limit);
int getrusage(int who, struct rusage *r_usage);
Здесь id_t
— это целочисленный тип, применяемый для идентификаторов пользователя и группы. Структура rusage
, указанная в файле sys/resource.h, используется для определения времени центрального процессора (ЦП), затраченного текущей программой. Она должна содержать, как минимум, два элемента (табл. 4.9).
Таблица 4.9
Элемент структуры rusage |
Описание |
---|---|
struct timeval ru_utime |
Время, использованное пользователем |
struct timeval ru_stime |
Время, использованное системой |
Структура timeval
определена в файле sys/time.h и содержит поля tv_sec
и tv_usec
, представляющие секунды и микросекунды соответственно.
Время ЦП, потребляемое программой, делится на время пользователя (время, затраченное самой программой на выполнение собственных инструкций) и системное время (время ЦП, потребляемое операционной системой в интересах программы, т.е. время, затраченное на системные вызовы, выполняющие ввод и вывод или другие системные функции).
Функция getrusage
записывает данные о времени ЦП в структуру rusage
, на которую указывает параметр r_usage
. Параметр who
может быть задан одной из констант, приведенных в табл. 4.10.
Таблица 4.10
Константа who |
Описание |
---|---|
RUSAGE_SELF |
Возвращает данные о потреблении только для текущей программы |
RUSAGE_CHILDREN |
Возвращает данные о потреблении и для дочерних процессов |
Мы будем обсуждать дочерние процессы и приоритеты задач в главе 11, но для полноты картины мы здесь упоминаем об их причастности к потреблению системных ресурсов. Пока достаточно сказать, что у каждой выполняющейся программы есть ассоциированный с ней приоритет, и чем выше приоритет программы, тем больше ей выделяется доступного времени ЦП.
Примечание
Обычные пользователи могут только снижать приоритеты своих программ, а не повышать их.
Приложения могут определять и изменять свои (и чужие) приоритеты с помощью функций getpriority
и setpriority
. Процесс, исследуемый или изменяемый с помощью этих функций, может быть задан идентификатором процесса, группы или пользователя. Параметр which
описывает, как следует интерпретировать параметр who
(табл. 4.11).
Таблица 4.11
Параметр which |
Описание |
---|---|
PRIO_PROCESS |
who — идентификатор процесса |
PRIO_PGRP |
who — идентификатор группы |
PRIO_USER |
who — идентификатор пользователя |
Итак, для определения приоритета текущего процесса вы можете выполнить следующий вызов:
priority = getpriority(PRIO_PROCESS, getpid());
Функция setpriority
позволяет задать новый приоритет, если это возможно.
По умолчанию приоритет равен 0. Положительные значения приоритета применяются для фоновых задач, которые выполняются, только когда нет задачи с более высоким приоритетом, готовой к выполнению. Отрицательные значения приоритета заставляют программу работать интенсивнее, выделяя большие доли доступного времени ЦП. Диапазон допустимых приоритетов — от -20 до +20. Часто это приводит к путанице, поскольку, чем выше числовое значение, тем ниже приоритет выполнения.
Функция getpriority
возвращает установленный приоритет в случае успешного завершения или -1 с переменной errno
, указывающей на ошибку. Поскольку значение -1 само по себе обозначает допустимый приоритет, переменную errno
перед вызовом функции getpriority
следует приравнять нулю и при возврате из функции проверить, осталась ли она нулевой. Функция setpriority
возвращает 0 в случае успешного завершения и -1 в противном случае.
Предельные величины, заданные для системных ресурсов, можно прочитать и установить с помощью функций getrlimit
и setrlimit
. Обе они для описания ограничений ресурсов используют структуру общего назначения rlimit
. Она определена в файле sys/resource.h и содержит элементы, перечисленные в табл. 4.12.
Таблица 4.12
Элемент rlimit |
Описание |
---|---|
rlim_t rlim_cur |
Текущее, мягкое ограничение |
rlim_t rlim_max |
Жесткое ограничение |
Определенный выше тип rlim_t
— целочисленный тип, применяемый для описания уровней ресурсов. Обычно мягкое ограничение — это рекомендуемое ограничение, которое не следует превышать; нарушение этой рекомендации может вызвать возврат ошибок из библиотечных функций. При превышении жесткого ограничения система может попытаться завершить программу, отправив ей сигнал, например, сигнал SIGXCPU
при превышении ограничения на потребляемое время ЦП и сигнал SIGSEGV
при превышении ограничения на объем данных. В программе можно самостоятельно задать для любых значений собственные мягкие ограничения, не превышающие жесткого ограничения. Допустимо уменьшение жесткого ограничения. Увеличить его может только программа, выполняющаяся с правами суперпользователя.
Ограничить можно ряд системных ресурсов. Эти ограничения описаны в параметре resource
функций rlimit
и определены в файле sys/resource.h, как показано в табл. 4.13.
Таблица 4.13
Параметр resource |
Описание |
---|---|
RLIMIT_CORE |
Ограничение размера файла дампа ядра, в байтах |
RLIMIT_CPU |
Ограничение времени ЦП, в секундах |
RLIMIT_DATA |
Ограничение размера сегмента data() , в байтах |
RLIMIT_FSIZE |
Ограничение размера файла, в байтах |
RLIMIT_NOFILE |
Ограничение количества открытых файлов |
RLIMIT_STACK |
Ограничение размера стека, в байтах |
RLIMIT_AS |
Ограничение доступного адресного пространства (стек и данные), в байтах |
В упражнении 4.15 показана программа limits.c, имитирующая типичное приложение. Она также задает и нарушает ограничения ресурсов.
Упражнение 4.16. Ограничения ресурсов
1. Включите заголовочные файлы для всех функций, которые вы собираетесь применять в данной программе:
#include <sys/types.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
2. Функция типа void
записывает 10 000 раз строку во временный файл и затем выполняет некоторые арифметические вычисления для загрузки ЦП:
void work() {
FILE *f;
int i;
double x = 4.5;
f = tmpfile();
for (i = 0; i < 10000; i++) {
fprintf(f, "Do some outputn");
if (ferror(f)) {
fprintf(stderr, "Error writing to temporary filen");
exit(1);
}
}
for (i = 0; i < 1000000; i++) x = log(x*x + 3.21);
}
3. Функция main
вызывает функцию work
, а затем применяет функцию getrusage для определения времени ЦП, использованного work
. Эта информация выводится на экран:
int main() {
struct rusage r_usage;
struct rlimit r_limit;
int priority;
work();
getrusage(RUSAGE_SELF, &r_usage);
printf("CPU usage: User = %ld.%06ld, System = %ld.%06ldn",
r_usage.ru_utime.tvsec, rusage.ru_utime.tv_usec,
r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec);
4. Далее она вызывает функции getpriority
и getrlimit
для выяснения текущего приоритета и ограничений на размер файла соответственно:
priority = getpriority(PRIO_PROCESS, getpid());
printf("Current priority = %dn", priority);
getrlimit(RLIMIT_FSIZE, &r_limit);
printf("Current FSIZE limit: soft = %ld, hard = %ldn",
r_limi t.rlim_cur, r_limit.rlim_max);
5. В заключение задайте ограничение размера файла с помощью функции setrlimit
и снова вызовите функцию work
, которая завершится с ошибкой, т.к. попытается создать слишком большой файл:
r_limit.rlim_cur = 2048;
r_limit.rlim_max = 4096;
printf("Setting a 2K file size limitn");
setrlimit(RLIMIT_FS1ZE, &r_limit);
work();
exit(0);
}
Выполнив эту программу, вы сможете увидеть, сколько затрачено времени ЦП, и текущий приоритет, с которым программа выполняется. После того как будет задан предельный размер файла, программа не сможет записать во временный файл более 2048 байтов.
$ cc -о limits limits.с -lm
$ ./limits
CPU usage: User = 0.140008, System = 0.020001
Current priority = 0
Current FSIZE limit: soft = -1, hard = -1
Setting a 2K file size limit
File size limit exceeded
Вы можете изменить приоритет программы, запустив ее с помощью команды nice
. Далее показано, как меняется приоритет на значение +10, и в результате программа выполняется немного дольше.
$ nice ./limits
CPU usage: User = 0.152009, System = 0.020001
Current priority = 10
Current FSIZE limit: soft = -1, hard = -1
Setting a 2K file size limit
File size limit exceeded
Как это работает
Программа limits вызывает функцию work
для имитации операций типичной программы. Она выполняет некоторые вычисления и формирует вывод, в данном случае около 150 Кбайт записывается во временный файл. Программа вызывает функции управления ресурсами для выяснения своего приоритета и ограничений на размер файла. В данном случае ограничения размеров файлов не заданы, поэтому можно создавать файл любого размера (если позволяет дисковое пространство). Затем программа задает свое ограничение размера файла, равное примерно 2 Кбайт, и снова пытается выполнить некоторые действия. На этот раз функция work
завершается неудачно, поскольку не может создать такой большой временный файл.
Примечание
Ограничения можно также наложить на программу, выполняющуюся в отдельной командной оболочке с помощью команды ulimit
оболочки bash.
В приведенном примере сообщение об ошибке "Error writing to temporary file" ("Ошибка записи во временный файл") не выводится. Это происходит потому, что некоторые системы (например, Linux 2.2 и более поздние версии) завершают выполнение программы при превышении ограничения ресурса. Делается это с помощью отправки сигнала SIGXFSZ
. В главе 11 вы узнаете больше о сигналах и способах их применения. Другие системы, соответствующие стандарту POSIX, заставляют функцию, превысившую ограничение, вернуть ошибку.
- 4. Ограничения ссылочной целостности
- Приложение 2 Интернет-ресурсы
- Приложение 3 Интернет-ресурсы
- Зарубежные интернет-ресурсы по XSLT
- 22.1. Ресурсы в Web
- Выявить возможные ограничения
- Темы как ресурсы
- 1.4.3 Лабораторная работа #4 "Программы и их ресурсы"
- Ограничения
- Недостатки и ограничения
- Погоны как функционал самоограничения
- Критические участки и состояние конкуренции за ресурсы