Однако существует атрибут, значение nice, который позволяет процессу опосредованно влиять на алгоритм планирования ядра. Каждый процесс имеет значение nice в диапазоне от –20 (высокий приоритет) до +19 (низкий приоритет); по умолчанию оно равно 0 (рис. 35.1). В традиционных реализациях UNIX только привилегированные процессы могут назначать себе (или другим процессам) отрицательный (высокий) приоритет (в подразделе 35.3.2 будут описаны некоторые особенности, характерные для Linux). Непривилегированные процессы могут только понижать свой приоритет, делая значение nice больше нуля. Делая это, они ведут себя «хорошо» (от англ.
Значение nice наследуется потомком, созданным с помощью fork(), и сохраняется на протяжении работы вызова exec().
Вместо непосредственного значения nice системный вызов getpriority() возвращает число в диапазоне от 1 (низкий приоритет) до 40 (высокий приоритет), вычисленное по формуле unice = 20 — knice. Это делается для того, чтобы избежать возвращения отрицательных значений, которые используются в системных вызовах для обозначения ошибок (описание работы системных вызовов ищите в разделе 3.1). Приложения не знают о том, что результатом работы системного вызова getpriority() является измененное значение, так как одноименная функция-обертка из библиотеки Си делает обратное вычисление, возвращается значение 20 — unice.
Рис. 35.1.
Значение nice не устанавливает четкой иерархии планирования процессов; вместо этого она играет роль весового коэффициента, на основе которого планировщик ядра выдает повышенные приоритеты. Процесс с низким приоритетом (то есть с высоким значением nice) не лишится процессорного времени полностью, но будет получать его в относительно меньших объемах. Степень влияния значения nice на планирование процессов зависит от версии ядра Linux или от конкретной UNIX-системы.
Начиная с версии 2.6.23, в ядре используется новый алгоритм планирования, согласно которому разница в значениях nice имеет большее влияние, чем раньше. В результате этого процессы с низкими и высокими значениям nice получают соответственно меньше и больше процессорного времени по сравнению с предыдущими версиями.
Системные вызовы getpriority() и setpriority() позволяют процессу получать и изменять свое собственное или чужое значение nice.
#include
int getpriority(int
Возвращает (возможно, отрицательное) значение nice заданного процесса или –1, если случилась ошибка
int setpriority(int
Возвращает 0 при успешном завершении или –1, если произошла ошибка
Оба системных вызова принимают аргументы which и who, определяющие процесс (-ы), приоритет которого (-ых) нужно получить или изменить. Первый влияет на то, как будет интерпретирован второй. Аргумент which может иметь одно из следующих значений.
• PRIO_PROCESS — работать с процессом, чей идентификатор равен who. Если who равен 0, используется идентификатор вызывающего процесса.
• PRIO_PGRP — работать со всеми участниками группы процессов, чей идентификатор PGID равен who. Если who равен 0, используется группа вызывающего процесса.
• PRIO_USER — работать со всеми процессами, реальный пользовательский идентификатор которых равен who. Если who равен 0, берется пользовательский идентификатор вызывающего процесса.
Тип данных id_t, который применяется для аргумента who, представляет собой целое число размера, достаточного для того, чтобы вместить идентификаторы процессов и пользователей.
Системный вызов getpriority() возвращает значение nice процесса, указанного с помощью аргументов which и who. Если заданным критериям отвечает сразу несколько процессов (это бывает, когда аргумент which равен PRIO_PGRP или PRIO_USER), берется процесс с самым высоким приоритетом. Поскольку getpriority() при успешном выполнении может вернуть –1, перед вызовом следует присваивать переменной errno значение 0 и затем, если мы получили –1, проверять, чему равна переменная errno после вызова.
Системный вызов setpriority() устанавливает значение nice(prio) для процесса (-ов), заданного (-ых) с помощью аргументов which и who. Если попытаться установить число, которое выходит за допустимые рамки (от –20 до +19), оно будет автоматически подогнано под корректное значение.
Изначально для изменения значений nice использовался вызов nice(incr), который добавлял incr к текущему значению. Эта функция все еще доступна, но ей на смену пришел более универсальный вызов, setpriority().