PTHREAD_ATTR_INIT(3) | Руководство программиста Linux | PTHREAD_ATTR_INIT(3) |
pthread_attr_init, pthread_attr_destroy - инициализирует и уничтожает объект атрибутов нити
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr); int pthread_attr_destroy(pthread_attr_t *attr);
Компилируется и компонуется вместе с -pthread.
Функция pthread_attr_init() инициализирует объект атрибутов нити, на который указывает attr, значениями атрибутов по умолчанию. После этого вызова отдельные атрибуты объекта можно изменять с помощью различных соответствующих функций (перечислены в разделе СМОТРИТЕ ТАКЖЕ, а после этого объект можно использовать в одном или нескольких вызовах pthread_create(3) для создания нитей.
Вызов pthread_attr_init() с уже инициализированным объектом атрибутов нити приводит к непредсказуемому поведению.
Когда объект атрибутов нити больше не нужен, он должен быть уничтожен с помощью функции pthread_attr_destroy(). Уничтожение объекта атрибутов нити не влияет на нить, которая была создана с использованием этого объекта.
После уничтожения объекта атрибутов нити его можно инициализировать с помощью pthread_attr_init() повторно. При использовании уничтоженного объекта атрибутов нити другим способом приводит непредсказуемым результатам.
При успешном выполнении эти функции возвращают 0; при ошибке возвращается ненулевой номер ошибки.
В POSIX.1 описана ошибка ENOMEM для pthread_attr_init(); в Linux эти функции всегда выполняются успешно (тем не менее, в переносимых приложениях нужно учитывать возможность возврата ошибки).
Описание терминов данного раздела смотрите в attributes(7).
Интерфейс | Атрибут | Значение |
pthread_attr_init(), pthread_attr_destroy() | Безвредность в нитях | MT-Safe |
POSIX.1-2001, POSIX.1-2008.
Тип pthread_attr_t должен считаться со скрытым форматом: любой доступ к объекту помимо функций pthreads является непереносимым и приводит к непредсказуемым результатам.
В программе, представленной ниже, для создания одной нити используется pthread_attr_init() и другие функции, относящиеся к инициализации объекта атрибутов нити. После создания в нити используется функция pthread_getattr_np(3) (нестандартное расширение GNU) для получения атрибутов нити, а затем показываются эти атрибуты.
Если программа запускается без аргументов командной строки, то аргумент attr функции pthread_create(3) равен NULL, и поэтому нить создаётся с атрибутами по умолчанию. При запуске программы на Linux/x86-32 с реализацией нитей NPTL мы увидим следующее:
$ ulimit -s # стек не ограничен ==> размер стека по умолчанию 2 МБ unlimited $ ./a.out Атрибуты нити: Состояние отсоединения = PTHREAD_CREATE_JOINABLE Область = PTHREAD_SCOPE_SYSTEM Унаследованный планировщик = PTHREAD_INHERIT_SCHED Алгоритм планирования = SCHED_OTHER Приоритет планирования = 0 Размер защиты = 4096 байт Адрес стека = 0x40196000 Размер стека = 0x201000 байт
Если в командной строке мы укажем размер стека, то программа инициализирует объект атрибутов нити, задаёт различные атрибуты в этом объекте и передаёт указатель на объект в вызов pthread_create(3). При запуске программы на Linux/x86-32 с реализацией нитей NPTL мы увидим следующее:
$ ./a.out 0x3000000 posix_memalign() выделен по адресу 0x40197000 Атрибуты нити: Состояние отсоединения = PTHREAD_CREATE_DETACHED Область = PTHREAD_SCOPE_SYSTEM Унаследованный планировщик = PTHREAD_EXPLICIT_SCHED Алгоритм планирования = SCHED_OTHER Приоритет планирования = 0 Размер защиты = 0 байт Адрес стека = 0x40197000 Размер стека = 0x3000000 байт
#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_pthread_attr(pthread_attr_t *attr, char *prefix) { int s, i; size_t v; void *stkaddr; struct sched_param sp; s = pthread_attr_getdetachstate(attr, &i); if (s != 0) handle_error_en(s, "pthread_attr_getdetachstate"); printf("%sСостояние отсоединения = %s\n", prefix, (i == PTHREAD_CREATE_DETACHED) ? "PTHREAD_CREATE_DETACHED" : (i == PTHREAD_CREATE_JOINABLE) ? "PTHREAD_CREATE_JOINABLE" : "???"); s = pthread_attr_getscope(attr, &i); if (s != 0) handle_error_en(s, "pthread_attr_getscope"); printf("%sОбласть = %s\n", prefix, (i == PTHREAD_SCOPE_SYSTEM) ? "PTHREAD_SCOPE_SYSTEM" : (i == PTHREAD_SCOPE_PROCESS) ? "PTHREAD_SCOPE_PROCESS" : "???"); s = pthread_attr_getinheritsched(attr, &i); if (s != 0) handle_error_en(s, "pthread_attr_getinheritsched"); printf("%sУнаследованный планировщик = %s\n", prefix, (i == PTHREAD_INHERIT_SCHED) ? "PTHREAD_INHERIT_SCHED" : (i == PTHREAD_EXPLICIT_SCHED) ? "PTHREAD_EXPLICIT_SCHED" : "???"); s = pthread_attr_getschedpolicy(attr, &i); if (s != 0) handle_error_en(s, "pthread_attr_getschedpolicy"); printf("%sАлгоритм планирования = %s\n", prefix, (i == SCHED_OTHER) ? "SCHED_OTHER" : (i == SCHED_FIFO) ? "SCHED_FIFO" : (i == SCHED_RR) ? "SCHED_RR" : "???"); s = pthread_attr_getschedparam(attr, &sp); if (s != 0) handle_error_en(s, "pthread_attr_getschedparam"); printf("%sПриоритет планирования = %d\n", prefix, sp.sched_priority); s = pthread_attr_getguardsize(attr, &v); if (s != 0) handle_error_en(s, "pthread_attr_getguardsize"); printf("%sРазмер защиты = %zu bytes\n", prefix, v); s = pthread_attr_getstack(attr, &stkaddr, &v); if (s != 0) handle_error_en(s, "pthread_attr_getstack"); printf("%sАдрес стека = %p\n", prefix, stkaddr); printf("%sРазмер стека = 0x%zx байт\n", prefix, v); } static void * thread_start(void *arg) { int s; pthread_attr_t gattr; /* pthread_getattr_np() — нестандартное расширение GNU, возвращает атрибуты нити, указанной в её первом аргументе */ s = pthread_getattr_np(pthread_self(), &gattr); if (s != 0) handle_error_en(s, "pthread_getattr_np"); printf("Атрибуты нити:\n"); display_pthread_attr(&gattr, "\t"); exit(EXIT_SUCCESS); /* Завершить все нити */ } int main(int argc, char *argv[]) { pthread_t thr; pthread_attr_t attr; pthread_attr_t *attrp; /* NULL или &attr */ int s; attrp = NULL; /* Если в командной строке есть аргумент, то использовать его для задания атрибута размера стека и ещё некоторых других атрибутов нити, и attrp будет указывать на объект атрибутов нити */ if (argc > 1) { int stack_size; void *sp; attrp = &attr; s = pthread_attr_init(&attr); if (s != 0) handle_error_en(s, "pthread_attr_init"); s = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); if (s != 0) handle_error_en(s, "pthread_attr_setdetachstate"); s = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); if (s != 0) handle_error_en(s, "pthread_attr_setinheritsched"); stack_size = strtoul(argv[1], NULL, 0); s = posix_memalign(&sp, sysconf(_SC_PAGESIZE), stack_size); if (s != 0) handle_error_en(s, "posix_memalign"); printf("posix_memalign() выделен по адресу %p\n", sp); s = pthread_attr_setstack(&attr, sp, stack_size); if (s != 0) handle_error_en(s, "pthread_attr_setstack"); } 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_setaffinity_np(3), pthread_attr_setdetachstate(3), pthread_attr_setguardsize(3), pthread_attr_setinheritsched(3), pthread_attr_setschedparam(3), pthread_attr_setschedpolicy(3), pthread_attr_setscope(3), pthread_attr_setstack(3), pthread_attr_setstackaddr(3), pthread_attr_setstacksize(3), pthread_create(3), pthread_getattr_np(3), pthread_setattr_default_np(3), pthreads(7)
2019-03-06 | Linux |