Linux
2019-03-06
man-pages-ru
Russian man pages from the Linux Documentation Project
manpages-dev
Manual pages about using GNU/Linux for development
man-pages
Linux kernel and C library user-space interface documentation
ИМЯ
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; при ошибке возвращается ненулевой номер ошибки.
ОШИБКИ
ENOMEM | Недостаточно памяти. |
ВЕРСИИ
Эта функция доступна в 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) байт
# размер стека по умолчанию 2 МБ unlimited $ ./a.out Атрибуты созданной нити:
Размер защиты = 4096 байт
Адрес стека = 0x40196000 (EOS = 0x40397000)
Размер стека = 0x201000 (2101248) байт
В этом запуске мы видим, что при задании размера защиты его значение округляется до значение следующего кратного размера системной страницы (4096 байт на x86-32):
$ ./a.out -g 4097 Объект атрибутов нити после инициализации:
Размер защиты = 4097 байт
Адрес стека = (nil)
Размер стека = 0x0 (0) байт
Размер защиты = 4097 байт
Адрес стека = (nil)
Размер стека = 0x0 (0) байт
Атрибуты созданной нити:
Размер защиты = 8192 байт
Адрес стека = 0x40196000 (EOS = 0x40397000)
Размер стека = 0x201000 (2101248) байт
Размер защиты = 8192 байт
Адрес стека = 0x40196000 (EOS = 0x40397000)
Размер стека = 0x201000 (2101248) байт
В этом запуске программа вручную выделяет стек для нити. В этом случае атрибут размера защиты игнорируется.
$ ./a.out -g 4096 -s 0x8000 -a Выделен стек нити по адресу 0x804d000
Объект атрибутов нити после инициализации:
Размер защиты = 4096 байт
Адрес стека = 0x804d000 (EOS = 0x8055000)
Размер стека = 0x8000 (32768) байт
Размер защиты = 4096 байт
Адрес стека = 0x804d000 (EOS = 0x8055000)
Размер стека = 0x8000 (32768) байт
Атрибуты созданной нити:
Размер защиты = 0 байт
Адрес стека = 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)
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;
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);
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); }
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;
int s;
pthread_attr_t attr;
s = pthread_getattr_np(thread, &attr);
if (s != 0)
handle_error_en(s, "pthread_getattr_np");
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"); }
if (s != 0)
handle_error_en(s, "pthread_attr_destroy"); }
static void * /* Начальная функция создаваемой нити */ thread_start(void *arg) {
printf("Атрибуты созданной нити:\n");
display_thread_attributes(pthread_self(), "\t");
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); }
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;
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 \(aqa\(aq: allocate_stack = 1; break;
case \(aqg\(aq: guard_size = strtoul(optarg, NULL, 0); break;
case \(aqs\(aq: stack_size = strtoul(optarg, NULL, 0); break;
default: usage(argv[0], NULL);
}
}
switch (opt) {
case \(aqa\(aq: allocate_stack = 1; break;
case \(aqg\(aq: guard_size = strtoul(optarg, NULL, 0); break;
case \(aqs\(aq: stack_size = strtoul(optarg, NULL, 0); break;
default: usage(argv[0], NULL);
}
}
if (allocate_stack && stack_size == -1)
usage(argv[0], "Указывать -a без -s не имеет смысла\n");
usage(argv[0], "Указывать -a без -s не имеет смысла\n");
if (argc > optind)
usage(argv[0], "Посторонние аргументы в командной строке\n");
usage(argv[0], "Посторонние аргументы в командной строке\n");
if (stack_size >= 0 || guard_size > 0) {
ret_attrp = attrp;
ret_attrp = attrp;
s = pthread_attr_init(attrp);
if (s != 0)
handle_error_en(s, "pthread_attr_init");
}
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);
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 (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");
}
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, если мы
инициализируем объект
атрибутов нити */
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");
}
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 (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");
}
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)