PTHREAD_GETATTR_NP(3) Руководство программиста Linux PTHREAD_GETATTR_NP(3)

ИМЯ

pthread_getattr_np - возвращает атрибуты созданной нити

ОБЗОР

#define _GNU_SOURCE             /* Смотрите feature_test_macros(7) */
#include <pthread.h>
int pthread_getattr_np(pthread_t thread, pthread_attr_t *attr);
Компилируется и компонуется вместе с -pthread.

ОПИСАНИЕ

Функция pthread_getattr_np() инициализирует объект атрибутов нити, на который указывает attr, так, чтобы он содержал актуальные значения атрибутов выполняющейся нити thread.

Возвращаемые значения атрибутов могут отличаться от соответствующих значений атрибутов переданных в объекте attr, который использовался при создании нити с помощью pthread_create(3). В частности, могут отличаться следующие атрибуты:

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

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

Когда объект атрибутов нити, возвращаемый pthread_getattr_np(), больше не требуется, то он должен быть удалён с помощью pthread_attr_destroy(3).

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

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

ОШИБКИ

Недостаточно памяти.

Также, если thread указывает на главную нить, то pthread_getattr_np() может завершиться с ошибкой из-за ошибок различных используемых вызовов: fopen(3), если невозможно открыть /proc/self/maps; getrlimit(2), если не поддерживается ограничение ресурса RLIMIT_STACK.

ВЕРСИИ

Эта функция доступна в glibc начиная с версии 2.2.3.

АТРИБУТЫ

Описание терминов данного раздела смотрите в attributes(7).

Интерфейс Атрибут Значение
pthread_getattr_np() Безвредность в нитях MT-Safe

СООТВЕТСТВИЕ СТАНДАРТАМ

Эта функция является нестандартным расширением GNU, о чём свидетельствует наличие суффикса «_np» (nonportable).

ПРИМЕР

В программе, показанной далее, демонстрируется использование pthread_getattr_np(). Программа создаёт нить, которая, затем, использует pthread_getattr_np() для получения и показа своих атрибутов размера защиты, адреса стека и размера стека. Аргументами командной строки можно изменить эти атрибуты. Работа программы показана далее.

В этом запуске на системе x86-32 нить создаётся со значениями атрибутов по умолчанию:

$ ulimit -s      # Без ограничения стека ==>

                 # размер стека по умолчанию 2 МБ
unlimited
$ ./a.out
Атрибуты созданной нити:

        Размер защиты      = 4096 байт

        Адрес стека        = 0x40196000 (EOS = 0x40397000)

        Размер стека       = 0x201000 (2101248) байт

В этом запуске мы видим, что при задании размера защиты его значение округляется до значение следующего кратного размера системной страницы (4096 байт на x86-32):

$ ./a.out -g 4097
Объект атрибутов нити после инициализации:

        Размер защиты      = 4097 байт

        Адрес стека        = (nil)

        Размер стека       = 0x0 (0) байт
Атрибуты созданной нити:

        Размер защиты      = 8192 байт

        Адрес стека        = 0x40196000 (EOS = 0x40397000)

        Размер стека       = 0x201000 (2101248) байт

В этом запуске программа вручную выделяет стек для нити. В этом случае атрибут размера защиты игнорируется.

$ ./a.out -g 4096 -s 0x8000 -a
Выделен стек нити по адресу 0x804d000
Объект атрибутов нити после инициализации:

        Размер защиты      = 4096 байт

        Адрес стека        = 0x804d000 (EOS = 0x8055000)

        Размер стека       = 0x8000 (32768) байт
Атрибуты созданной нити:

        Размер защиты      = 0 байт

        Адрес стека        = 0x804d000 (EOS = 0x8055000)

        Размер стека       = 0x8000 (32768) байт

Исходный код программы

#define _GNU_SOURCE     /* для объявления pthread_getattr_np() */
#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
display_stack_related_attributes(pthread_attr_t *attr, char *prefix)
{

    int s;

    size_t stack_size, guard_size;

    void *stack_addr;

    s = pthread_attr_getguardsize(attr, &guard_size);

    if (s != 0)

        handle_error_en(s, "pthread_attr_getguardsize");

    printf("%sРазмер защиты            = %d байт\n", prefix, guard_size);

    s = pthread_attr_getstack(attr, &stack_addr, &stack_size);

    if (s != 0)

        handle_error_en(s, "pthread_attr_getstack");

    printf("%sАдрес стека       = %p", prefix, stack_addr);

    if (stack_size > 0)

        printf(" (EOS = %p)", (char *) stack_addr + stack_size);

    printf("\n");

    printf("%sРазмер стека          = 0x%x (%d) байт\n",

            prefix, stack_size, stack_size);
}
static void
display_thread_attributes(pthread_t thread, char *prefix)
{

    int s;

    pthread_attr_t attr;

    s = pthread_getattr_np(thread, &attr);

    if (s != 0)

        handle_error_en(s, "pthread_getattr_np");

    display_stack_related_attributes(&attr, prefix);

    s = pthread_attr_destroy(&attr);

    if (s != 0)

        handle_error_en(s, "pthread_attr_destroy");
}
static void *           /* Начальная функция создаваемой нити */
thread_start(void *arg)
{

    printf("Атрибуты созданной нити:\n");

    display_thread_attributes(pthread_self(), "\t");

    exit(EXIT_SUCCESS);         /* Завершить все нити */
}
static void
usage(char *pname, char *msg)
{

    if (msg != NULL)

        fputs(msg, stderr);

    fprintf(stderr, "Использование: %s [-s stack-size [-a]]"

            " [-g guard-size]\n", pname);

    fprintf(stderr, "\t\t-a означает, что программа выделяет стек\n");

    exit(EXIT_FAILURE);
}
static pthread_attr_t *   /* получить атрибуты нити из ком. строки */
get_thread_attributes_from_cl(int argc, char *argv[],

                              pthread_attr_t *attrp)
{

    int s, opt, allocate_stack;

    long stack_size, guard_size;

            void *stack_addr;

    pthread_attr_t *ret_attrp = NULL;   /* задаёт attrp, если мы

                                           инициализируем объект

                                           атрибутов нити */

    allocate_stack = 0;

    stack_size = -1;

    guard_size = -1;

    while ((opt = getopt(argc, argv, "ag:s:")) != -1) {

        switch (opt) {

        case 'a':   allocate_stack = 1;                     break;

        case 'g':   guard_size = strtoul(optarg, NULL, 0);  break;

        case 's':   stack_size = strtoul(optarg, NULL, 0);  break;

        default:    usage(argv[0], NULL);

        }

    }

    if (allocate_stack && stack_size == -1)

        usage(argv[0], "Указывать -a без -s не имеет смысла\n");

    if (argc > optind)

        usage(argv[0], "Посторонние аргументы в командной строке\n");

    if (stack_size >= 0 || guard_size > 0) {

        ret_attrp = attrp;

        s = pthread_attr_init(attrp);

        if (s != 0)

            handle_error_en(s, "pthread_attr_init");

    }

    if (stack_size >= 0) {

        if (!allocate_stack) {

            s = pthread_attr_setstacksize(attrp, stack_size);

            if (s != 0)

                handle_error_en(s, "pthread_attr_setstacksize");

        } else {

            s = posix_memalign(&stack_addr, sysconf(_SC_PAGESIZE),

                               stack_size);

            if (s != 0)

                handle_error_en(s, "posix_memalign");

            printf("Выделен стек нити по адресу %p\n\n", stack_addr);

            s = pthread_attr_setstack(attrp, stack_addr, stack_size);

            if (s != 0)

                handle_error_en(s, "pthread_attr_setstacksize");

        }

    }

    if (guard_size >= 0) {

        s = pthread_attr_setguardsize(attrp, guard_size);

        if (s != 0)

            handle_error_en(s, "pthread_attr_setstacksize");

    }

    return ret_attrp;
}
int
main(int argc, char *argv[])
{

    int s;

    pthread_t thr;

    pthread_attr_t attr;

    pthread_attr_t *attrp = NULL;    /* задаёт &attr, если мы

                                        инициализируем объект

                                        атрибутов нити */

    attrp = get_thread_attributes_from_cl(argc, argv, &attr);

    if (attrp != NULL) {

        printf("Объект атрибутов нити после инициализации:\n");

        display_stack_related_attributes(attrp, "\t");

        printf("\n");

    }

    s = pthread_create(&thr, attrp, &thread_start, NULL);

    if (s != 0)

        handle_error_en(s, "pthread_create");

    if (attrp != NULL) {

        s = pthread_attr_destroy(attrp);

        if (s != 0)

            handle_error_en(s, "pthread_attr_destroy");

    }

    pause();    /* Завершается, когда другая нить вызывает exit() */
}

СМОТРИТЕ ТАКЖЕ

pthread_attr_getaffinity_np(3), pthread_attr_getdetachstate(3), pthread_attr_getguardsize(3), pthread_attr_getinheritsched(3), pthread_attr_getschedparam(3), pthread_attr_getschedpolicy(3), pthread_attr_getscope(3), pthread_attr_getstack(3), pthread_attr_getstackaddr(3), pthread_attr_getstacksize(3), pthread_attr_init(3), pthread_create(3), pthreads(7)

2019-03-06 Linux