PTHREAD_SETSCHEDPARAM(3)

ИМЯ
pthread_setschedparam, pthread_getschedparam - изменяет/возвращает параметры и алгоритм планирования нити

ОБЗОР
#include <pthread.h>

int pthread_setschedparam(pthread_t thread, int policy,
                          const struct sched_param *param);
int pthread_getschedparam(pthread_t thread, int *policy,
                          struct sched_param *param);

Компилируется и компонуется вместе с -pthread.

ОПИСАНИЕ
Функция pthread_setschedparam() назначает параметры и алгоритм планирования нити thread.

В policy указывается новый алгоритм планирования thread. Поддерживаемые значения policy и их семантика описана в sched(7).

Структура, на которую указывает param определяет новые параметры планирования thread. Параметры планирования хранятся в структуре следующего вида:

    struct sched_param {
        int sched_priority;     /* планируемый приоритет */
    };

Из той структуры видно, что поддерживается только один параметр. Подробности о разрешённых диапазонах планируемых приоритетов для каждого алгоритма планирования смотрите в sched(7).

Функция pthread_getschedparam() возвращает параметры и алгоритм планирования нити thread в буфер, указанный policy и param, соответственно. Возвращаемое значение приоритета совпадает с заданным с помощью последнего вызова pthread_setschedparam(), pthread_setschedprio(3) или pthread_create(3), относящегося к thread. Возвращаемые приоритет не отражает каких-либо временных подстроек приоритета в результате вызовов функций наследования приоритета или потолка (например, смотрите pthread_mutexattr_setprioceiling(3) и pthread_mutexattr_setprotocol(3)).

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении эти функции возвращают 0; при ошибке возвращается ненулевой номер ошибки. Если pthread_setschedparam() завершается ошибкой, то параметры и алгоритм планирования thread не изменяется.

ОШИБКИ
Это функции могут завершиться со следующей ошибкой:

ESRCH
    Нить с идентификатором thread не найдена.

Функция pthread_setschedparam() может также завершиться со следующими ошибками:

EINVAL
    Неизвестное значение policy или значение param не имеет смысла для policy.

EPERM
    Вызывающий не имеет соответствующих прав для установки указанного алгоритма планирования и параметров.

Для pthread_setschedparam() в POSIX.1 также описана необязательная ошибка ENOTSUP («попытка изменить параметры и алгоритм планирования на не поддерживаемое значение»).

АТРИБУТЫ
Описание терминов данного раздела смотрите в attributes(7).
Интерфейс | Атрибут | Значение
pthread_setschedparam(), pthread_getschedparam() | Безвредность в нитях | MT-Safe

СООТВЕТСТВИЕ СТАНДАРТАМ
POSIX.1-2001, POSIX.1-2008.

ЗАМЕЧАНИЯ
Список требуемых прав, результат, изменение алгоритма и приоритета планирования нити и подробности разрешённых диапазонов приоритетов для каждого алгоритма планирования смотрите в sched(7).

ПРИМЕР
Представленная ниже программа показывает использование pthread_setschedparam() и pthread_getschedparam(), а также других относящихся к планированию функций программного интерфейса pthreads.

В этом сеансе, главная нить изменяет свой алгоритм планирования на SCHED_FIFO с приоритетом 10, и инициализирует объект атрибутов нити с атрибутом алгоритма планирования SCHED_RR и атрибутом приоритета планирования 20. Затем программа изменяет (с помощью pthread_attr_setinheritsched(3)) атрибут наследования планировщика в объекте атрибутов нити на PTHREAD_EXPLICIT_SCHED, из-за чего создаваемые с использованием данного объекта атрибутов нити получат значения атрибуты планирования из объекта атрибутов нити. Затем программа создаёт нить с учётом объекта атрибутов нити, после чего эта нить выводит значения своего алгоритма и приоритета планирования.

    $ su      # требуются права для назначения алгоритмов
                планирования реального времени
    Пароль:
    # ./a.out -mf10 -ar20 -i e
    Настройки планировщика главной нити
        алгоритм=SCHED_FIFO, приоритет=10
    Настройки планировщика в 'attr'
        алгоритм=SCHED_RR, приоритет=20
        наследование планировщика ЯВНОЕ
    Атрибуты планировщика в новой нити
        алгоритм=SCHED_RR, приоритет=20

В показанном выше выводе можно видеть приоритет и алгоритм планирования, которые были взяты из объекта атрибутов нити.

Следующий сеанс похож на предыдущий, то в нём атрибут наследования планировщика равен PTHREAD_INHERIT_SCHED, то есть создаваемые с использованием объекта атрибутов нити игнорируют значения параметров и алгоритм планирования, заданные в объекте атрибутов нити, и берут их от создавшей нити.

    # ./a.out -mf10 -ar20 -i i
    Настройки планировщика главной нити
        алгоритм=SCHED_FIFO, приоритет=10
    Настройки планировщика в 'attr'
        алгоритм=SCHED_RR, приоритет=20
        наследование планировщика ВКЛЮЧЕНО
    Атрибуты планировщика в новой нити
        алгоритм=SCHED_FIFO, приоритет=10

В показанном выше выводе можно видеть приоритет и алгоритм планирования, которые были взяты из создаваемой нити, а не из объекта атрибутов нити.

Заметим, чти если не указать параметр -i i, то вывод будет тем же самым, так как PTHREAD_INHERIT_SCHED является значением по умолчанию для атрибута наследования планировщика.

  Исходный код программы
    /* pthreads_sched_test.c */
    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <errno.h>
    #define handle_error_en(en, msg) \
            do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
    static void
    usage(char *prog_name, char *msg)
    {
        if (msg != NULL)
            fputs(msg, stderr);
        fprintf(stderr, "Использование: %s [параметры]\n", prog_name);
        fprintf(stderr, "Параметры:\n");
    #define fpe(msg) fprintf(stderr, "\t%s", msg);       /* для краткости */
        fpe("-a<алгоритм><приоритет> Алгоритм и приоритет планирования\n");
        fpe("                 объекте атрибутов нити\n");
        fpe("                 значения для <алгоритм>:\n");
        fpe("                     f  SCHED_FIFO\n");
        fpe("                     r  SCHED_RR\n");
        fpe("                     o  SCHED_OTHER\n");
        fpe("-A               Исп. объект атрибутов нити по умолчанию\n");
        fpe("-i {e|i}         Атрибут наследования планировщика\n");
        fpe("                 'явный' or 'унаследованный'\n");
        fpe("-m<алгоритм><приоритет> Алгоритм и приоритет планирования\n");
        fpe("               главной нити перед вызовом pthread_create()\n");
        exit(EXIT_FAILURE);
    }
    static int
    get_policy(char p, int *policy)
    {
        switch (p) {
        case 'f': *policy = SCHED_FIFO;     return 1;
        case 'r': *policy = SCHED_RR;       return 1;
        case 'o': *policy = SCHED_OTHER;    return 1;
        default:  return 0;
        }
    }
    static void
    display_sched_attr(int policy, struct sched_param *param)
    {
        printf("    алгоритм=%s, приоритет=%d\n",
                (policy == SCHED_FIFO)  ? "SCHED_FIFO" :
                (policy == SCHED_RR)    ? "SCHED_RR" :
                (policy == SCHED_OTHER) ? "SCHED_OTHER" :
                "???",
                param->sched_priority);
    }
    static void
    display_thread_sched_attr(char *msg)
    {
        int policy, s;
        struct sched_param param;
        s = pthread_getschedparam(pthread_self(), &policy, &param);
        if (s != 0)
            handle_error_en(s, "pthread_getschedparam");
        printf("%s\n", msg);
        display_sched_attr(policy, &param);
    }
    static void *
    thread_start(void *arg)
    {
        display_thread_sched_attr("Атрибуты планировщика в новой нити");
        return NULL;
    }
    int
    main(int argc, char *argv[])
    {
        int s, opt, inheritsched, use_null_attrib, policy;
        pthread_t thread;
        pthread_attr_t attr;
        pthread_attr_t *attrp;
        char *attr_sched_str, *main_sched_str, *inheritsched_str;
        struct sched_param param;
        /* обработка параметров командной строки */
        use_null_attrib = 0;
        attr_sched_str = NULL;
        main_sched_str = NULL;
        inheritsched_str = NULL;
        while ((opt = getopt(argc, argv, "a:Ai:m:")) != -1) {
            switch (opt) {
            case 'a': attr_sched_str = optarg;      break;
            case 'A': use_null_attrib = 1;          break;
            case 'i': inheritsched_str = optarg;    break;
            case 'm': main_sched_str = optarg;      break;
            default:  usage(argv[0], "Неизвестный параметр\n");
            }
        }
        if (use_null_attrib &&
                (inheritsched_str != NULL || attr_sched_str != NULL))
            usage(argv[0], "Нельзя указывать -A вместе с -i или -a\n");
        /* необязательная установка атрибутов планирования главной нити
           вывод этих атрибутов */
        if (main_sched_str != NULL) {
            if (!get_policy(main_sched_str[0], &policy))
                usage(argv[0], "Некоррект. алгоритм для главной нити (-m)\n");
            param.sched_priority = strtol(&main_sched_str[1], NULL, 0);
            s = pthread_setschedparam(pthread_self(), policy, &param);
            if (s != 0)
                handle_error_en(s, "pthread_setschedparam");
        }
        display_thread_sched_attr("Настройки планировщика главной нити");
        printf("\n");
        /* инициализация объекта атрибутов нити согласно параметрам */
        attrp = NULL;
        if (!use_null_attrib) {
            s = pthread_attr_init(&attr);
            if (s != 0)
                handle_error_en(s, "pthread_attr_init");
            attrp = &attr;
        }
        if (inheritsched_str != NULL) {
            if (inheritsched_str[0] == 'e')
                inheritsched = PTHREAD_EXPLICIT_SCHED;
            else if (inheritsched_str[0] == 'i')
                inheritsched = PTHREAD_INHERIT_SCHED;
            else
                usage(argv[0], "Значение -i должно быть 'e' или 'i'\n");
            s = pthread_attr_setinheritsched(&attr, inheritsched);
            if (s != 0)
                handle_error_en(s, "pthread_attr_setinheritsched");
        }
        if (attr_sched_str != NULL) {
            if (!get_policy(attr_sched_str[0], &policy))
                usage(argv[0],
                        "Некорректный алгоритм для 'attr' (-a)\n");
            param.sched_priority = strtol(&attr_sched_str[1], NULL, 0);
            s = pthread_attr_setschedpolicy(&attr, policy);
            if (s != 0)
                handle_error_en(s, "pthread_attr_setschedpolicy");
            s = pthread_attr_setschedparam(&attr, &param);
            if (s != 0)
                handle_error_en(s, "pthread_attr_setschedparam");
        }
        /* если мы инициализируем объект атрибутов нити, то покажем
           атрибуты планирования, установленные в объекте */
        if (attrp != NULL) {
            s = pthread_attr_getschedparam(&attr, &param);
            if (s != 0)
                handle_error_en(s, "pthread_attr_getschedparam");
            s = pthread_attr_getschedpolicy(&attr, &policy);
            if (s != 0)
                handle_error_en(s, "pthread_attr_getschedpolicy");
            printf("Настройки планировщика в 'attr'\n");
            display_sched_attr(policy, &param);
            s = pthread_attr_getinheritsched(&attr, &inheritsched);
            printf("    наследование планировщика %s\n",
                    (inheritsched == PTHREAD_INHERIT_SCHED)  ? "ВКЛЮЧЕНО" :
                    (inheritsched == PTHREAD_EXPLICIT_SCHED) ? "ЯВНОЕ" :
                    "???");
            printf("\n");
        }
        /* создаём нить, которая покажет свои атрибуты планирования */
        s = pthread_create(&thread, attrp, &thread_start, NULL);
        if (s != 0)
            handle_error_en(s, "pthread_create");
        /* уничтожаем ненужный объект атрибутов нити */
        if (!use_null_attrib) {
          s = pthread_attr_destroy(&attr);
          if (s != 0)
              handle_error_en(s, "pthread_attr_destroy");
        }
        s = pthread_join(thread, NULL);
        if (s != 0)
            handle_error_en(s, "pthread_join");
        exit(EXIT_SUCCESS);
    }

СМОТРИТЕ ТАКЖЕ
getrlimit(2), sched_get_priority_min(2), pthread_attr_init(3), pthread_attr_setinheritsched(3), pthread_attr_setschedparam(3), pthread_attr_setschedpolicy(3), pthread_create(3), pthread_self(3), pthread_setschedprio(3), pthreads(7), sched(7)