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). В частности, могут отличаться следующие атрибуты:
Кроме этого, если атрибут адреса стека не был указан в объекте атрибутов нити при создании нити, то возвращаемый объект атрибутов нити будет содержать актуальный адрес стека, который был выбран реализацией для нити.
Когда объект атрибутов нити, возвращаемый 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 |