Опубликован: 06.12.2004 | Доступ: свободный | Студентов: 1182 / 144 | Оценка: 4.76 / 4.29 | Длительность: 20:58:00
ISBN: 978-5-9556-0021-5
Лекция 1:

Потоки управления

Лекция 1: 1234567 || Лекция 2 >

Описанный выше атрибут "область планирования конкуренции", способный принимать значения PTHREAD_SCOPE_SYSTEM и PTHREAD_SCOPE_PROCESS, обслуживают функции pthread_attr_getscope() и pthread_attr_setscope() (см. листинг 1.8).

#include <pthread.h>

int pthread_attr_getscope (
    const pthread_attr_t *restrict attr,
    int *restrict contentionscope);

int pthread_attr_setscope (
    pthread_attr_t *attr, 
    int contentionscope);
Листинг 1.8. Описание функций pthread_attr_getscope() и pthread_attr_setscope().

При создании потока управления все рассмотренные выше атрибуты планирования, в зависимости от значения PTHREAD_INHERIT_SCHED или PTHREAD_EXPLICIT_SCHED атрибута inheritsched, могут наследоваться у создающего потока или извлекаться из атрибутного объекта. Для опроса и изменения этого атрибута предназначены функции pthread_attr_getinheritsched() и pthread_attr_setinheritsched() (см. листинг 1.9).

#include <pthread.h>

int pthread_attr_getinheritsched (
    const pthread_attr_t *restrict attr,
    int *restrict inheritsched);

int pthread_attr_setinheritsched (
    pthread_attr_t *attr, 
    int inheritsched);
Листинг 1.9. Описание функций pthread_attr_getinheritsched() и pthread_attr_setinheritsched().

Атрибут обособленности потока управления, присутствующий в атрибутном объекте, можно опросить и установить посредством функций pthread_attr_getdetachstate() и pthread_attr_setdetachstate() (см. листинг 1.10).

#include <pthread.h>

int pthread_attr_getdetachstate (
    const pthread_attr_t *attr, 
    int *detachstate);

int pthread_attr_setdetachstate (
    pthread_attr_t *attr, 
    int detachstate);
Листинг 1.10. Описание функций pthread_attr_getdetachstate() и pthread_attr_setdetachstate().

Напомним, что значение этого атрибута ( PTHREAD_CREATE_DETACHED или PTHREAD_CREATE_JOINABLE ) определяет, будет ли поток управления создан как обособленный или присоединяемый, то есть доступный другим потокам для ожидания завершения. Подразумеваемым является значение PTHREAD_CREATE_JOINABLE.

Значения атрибутов планирования могут задаваться не только при создании потока управления. Стандарт POSIX-2001 предоставляет средства для их динамического изменения и опроса (см. листинг 1.11).

#include <pthread.h>

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


int pthread_setschedparam (
    pthread_t thread, int policy,
    const struct sched_param *param);
Листинг 1.11. Описание функций pthread_getschedparam() и pthread_setschedparam().

Отметим две тонкости, связанные с функцией pthread_setschedparam(). Во-первых, возможно, что для ее успешного вызова процесс должен обладать соответствующими привилегиями. Во-вторых, реализация не обязана поддерживать динамический переход к политике спорадического планирования ( SCHED_SPORADIC ) (как, впрочем, и саму эту политику ).

Если требуется изменить лишь приоритет планирования, не меняя политику, проще воспользоваться функцией pthread_setschedprio() (см. листинг 1.12), которая, правда, является новой и в исторически сложившихся реализациях может отсутствовать.

#include <pthread.h>
int pthread_setschedprio (
    pthread_t thread, int prio);
Листинг 1.12. Описание функции pthread_setschedprio().

Сходную направленность, но более глобальный характер имеют функции pthread_getconcurrency() и pthread_setconcurrency() (см. листинг 1.13), позволяющие опросить и изменить уровень параллелизма выполнения потоков управления.

#include <pthread.h>

int pthread_getconcurrency (void);

int pthread_setconcurrency (int new_level);
Листинг 1.13. Описание функций pthread_getconcurrency() и pthread_setconcurrency().

По умолчанию операционная система предоставляет возможность параллельно проявлять активность некоему "достаточному числу" потоков управления в процессе, так, чтобы это не вело к перерасходу системных ресурсов. Некоторым приложениям, однако, может требоваться более высокий уровень параллелизма ; это требование они могут передать ОС в виде значения аргумента new_level функции pthread_setconcurrency(). Впрочем, с точки зрения операционной системы это всего лишь просьба или рекомендация; стандарт не специфицирует реально устанавливаемый уровень.

Нулевое значение аргумента new_level означает переход к подразумеваемому уровню параллелизма, как если бы функция pthread_setconcurrency() ранее не вызывалась.

Функция pthread_getconcurrency() в качестве результата возвращает значение уровня параллелизма, установленное предыдущим вызовом pthread_setconcurrency(). Если такового не было, выдается нуль.

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

К числу атрибутов потока управления можно отнести обслуживающие его часы процессорного времени. Для выяснения их идентификатора достаточно обратиться к функции pthread_getcpuclockid() (см. листинг 1.14).

#include <pthread.h>
#include <time.h>

int pthread_getcpuclockid (
    pthread_t thread_id, 
    clockid_t *clock_id);
Листинг 1.14. Описание функции pthread_getcpuclockid().

Еще один атрибут потока управлениямаска блокированных сигналов. Поток может опросить и/или изменить ее посредством вызова функции pthread_sigmask() (см. листинг 1.15) – аналога рассмотренной в курсе [1] функции sigprocmask().

#include <signal.h>
int pthread_sigmask (
    int how, const sigset_t *restrict set,
    sigset_t *restrict oset);
Листинг 1.15. Описание функции pthread_sigmask().

На листинге 1.16 приведен пример программы, использующей большинство описанных выше функций для опроса и изменения атрибутов потоков управления. Возможные результаты работы этой программы показаны на листинге 1.17.

/* * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Программа опрашивает атрибуты потоков управления     */
/* и изменяет некоторые из них     */
/* * * * * * * * * * * * * * * * * * * * * * * * * * */

#define _XOPEN_SOURCE 600

#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <assert.h>

int main (void) {
    pthread_t ct_id;      /* Идентификатор текущего потока управления */
    pthread_attr_t patob; /* Атрибутный объект для создания    потоков управления     */
    int res;              /* Переменная для запоминания результатов "потоковых" функций */
void *stackaddr;          /* Начало стека как атрибут потока управления */
    size_t atrsize;       /* Размеры как атрибуты потока управления */
            /* Структура с параметрами планирования */
    struct sched_param shdprm;
    char *spname;     /* Названия политики планирования, области */
                        /* планирования конкуренции и т.п. */

    printf ("Идентификатор текущего потока управления: %lx\n",
             (ct_id = pthread_self ()));

        if ((errno = pthread_attr_init (&patob)) != 0) {
                perror ("PTHREAD_ATTR_INIT");
                return (errno);
    }

    printf ("Значения, установленные системой "
                "в атрибутном объекте\n");

    if ((errno = pthread_attr_getstack (&patob, &stackaddr, 
            &atrsize)) != 0) {
        perror ("PTHREAD_ATTR_GETSTACK");
        return (errno);
    }
    printf ("Адрес начала стека: %p\n", stackaddr);
    printf ("Размер стека: %d\n", atrsize);

    assert (pthread_attr_getguardsize (&patob, &atrsize) == 0);
    printf ("Размер защитной области: %d\n", atrsize);

    assert (pthread_attr_getschedparam (&patob, &shdprm) == 0);
    assert (pthread_attr_getschedpolicy (&patob, &res) == 0);
    switch (res) {
        case SCHED_FIFO:
            spname = "Планирование по очереди";
            break;
        case SCHED_RR:
            spname = "Циклическое планирование";
            break;
        case SCHED_OTHER:
            spname = "Прочее планирование";
            break;
        default:
            spname = "Неизвестная политика планирования";
    }
    printf ("Политика планирования: %s\n", spname);
    printf ("Приоритет планирования: %d\n", 
                    shdprm.sched_priority);

    assert (pthread_attr_getscope (&patob, &res) == 0);
    switch (res) {
        case PTHREAD_SCOPE_SYSTEM:
            spname = "Система";
            break;
        case PTHREAD_SCOPE_PROCESS:
            spname = "Процесс";
            break;
        default:
            spname = "Неизвестная область планирования "
                            "конкуренции";
    }
    printf ("Область планирования конкуренции: %s\n", spname);

    assert (pthread_attr_getinheritsched (&patob, &res) == 0);
    switch (res) {
        case PTHREAD_INHERIT_SCHED:
            spname = "Наследуются у родительского потока";
            break;
        case PTHREAD_EXPLICIT_SCHED:
            spname = "Извлекаются из атрибутного объекта";
            break;
        default:
            spname = "Устанавливаются неизвестным образом";
    }
    printf ("Атрибуты планирования: %s\n", spname);

    assert (pthread_attr_getdetachstate (&patob, &res) == 0);
    switch (res) {
        case PTHREAD_CREATE_JOINABLE:
            spname = "Присоединяемые";
            break;
        case PTHREAD_CREATE_DETACHED:
            spname = "Обособленные";
            break;
        default:
            spname = "Неизвестные";
    }
    printf ("Потоки управления создаются как: %s\n", spname);

    /* Изменим значения атрибутов планирования и уровня */
    /* параллелизма */
    shdprm.sched_priority = 1;
    if ((errno = pthread_setschedparam (ct_id, SCHED_RR, 
            &shdprm)) != 0) {
        perror ("PTHREAD_SETSCHEDPARAM");
    }
    if ((errno = pthread_setconcurrency (8192)) != 0) {
        perror ("PTHREAD_SETCONCURRENCY");
    }
    printf ("\nТекущие значения атрибутов потоков управления\n");

assert (pthread_getschedparam (ct_id, &res, &shdprm) == 0);
    switch (res) {
        case SCHED_FIFO:
            spname = "Планирование по очереди";
            break;
        case SCHED_RR:
            spname = "Циклическое планирование";
            break;
        case SCHED_OTHER:
            spname = "Прочее планирование";
            break;
        default:
            spname = "Неизвестная политика планирования";
    }
    printf ("Политика планирования: %s\n", spname);
    printf ("Приоритет планирования: %d\n", 
                    shdprm.sched_priority);
    printf ("Уровень параллелизма: %d\n", 
                    pthread_getconcurrency());

    return 0;
}
Листинг 1.16. Пример программы, опрашивающей и изменяющей значения атрибутов потоков управления.
Идентификатор текущего потока управления: 400 
Значения, установленные системой в атрибутном объекте
    Адрес начала стека: 0xffe01000
    Размер стека: 2093056
    Размер защитной области: 4096
    Политика планирования: Прочее планирование
    Приоритет планирования: 0
    Область планирования конкуренции: Система
    Атрибуты планирования: Извлекаются из атрибутного объекта
    Потоки управления создаются как: Присоединяемые

Текущие значения атрибутов потоков управления
    Политика планирования: Циклическое планирование
    Приоритет планирования: 1
    Уровень параллелизма: 8192
Листинг 1.17. Возможные результаты работы программы, опрашивающей и изменяющей значения атрибутов потоков управления.

Листинг 1.18 содержит результаты выполнения упрощенного варианта этой же программы (без вызовов функций pthread_attr_getstack(), pthread_attr_getguardsize(), pthread_getconcurrency(), pthread_setconcurrency() и без соответствующих выдач) для операционной системы реального времени oc2000, соответствующей подмножеству требований стандарта POSIX-2001.

Идентификатор текущего потока управления: f31ae0 
Значения, установленные системой в атрибутном объекте
    Политика планирования: Планирование по очереди
    Приоритет планирования: 100
    Область планирования конкуренции: Процесс
    Атрибуты планирования: Извлекаются из атрибутного объекта
    Потоки управления создаются как: Присоединяемые

Текущие значения атрибутов потоков управления
    Политика планирования: Циклическое планирование
    Приоритет планирования: 1
Листинг 1.18. Возможные результаты работы программы, опрашивающей и изменяющей значения атрибутов потоков управления, для операционной системы реального времени oc2000.
Лекция 1: 1234567 || Лекция 2 >