pthread_create

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



ИМЯ
       pthread_create - создаёт новую нить

ОБЗОР
       #include <pthread.h>

       int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

       Компилируется и компонуется вместе с -pthread.

ОПИСАНИЕ
       Функция pthread_create() запускает новую нить в вызвавшем процессе. Новая
       нить начинает выполнение вызовом start_routine(); значение arg является
       единственным аргументом start_routine().

       Новая нить завершает работу в одном из следующих случаев:

       * Она вызывает pthread_exit(3), указывая код выхода, доступное другой
         нити в том же процессе, вызвавшей pthread_join(3).

       * При возврате из start_routine(). Это эквивалентно вызову
         pthread_exit(3) со значением, переданным в операторе return.

       * При её отмене (смотрите pthread_cancel(3)).

       * При вызове из любой нити процесса функции exit(3), или если главная
         нить выполняет возврат из main(). Это вызывает завершение всех нитей
         процесса.

       Аргумент attr указывает на структуру pthread_attr_t, чьё содержимое
       используется при создании нити для определения атрибутов новой нити; эта
       структура инициализируется с помощью pthread_attr_init(3) и подобными
       функциями. Если значение attr равно NULL, то нити создаётся с атрибутами
       по умолчанию.

       Перед возвратом успешный вызов pthread_create() сохраняет ID новой нити в
       буфер, на который указывает thread; этот идентификатор используется для
       ссылки на нить в последующих вызовах других функций pthreads.

       Новая нить наследует копию сигнальной маски создавшей нити
       (pthread_sigmask(3)). Набор ожидающих сигналов новой нити пуст
       (sigpending(2)). Новая нить не наследует альтернативный стек сигналов
       создавшей нити (sigaltstack(2)).

       Новая нить наследует окружение плавающей запятой вызвавшей нити
       (fenv(3)).

       Начальное значение часов ЦП новой нити равно 0 (смотрите
       pthread_getcpuclockid(3)).

   Информация, касающаяся только Linux
       Новая нить наследует копию набора мандатов вызвавшей нити (смотрите
       capabilities(7)) и маску увязывания ЦП (смотрите sched_setaffinity(2)).

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
       При успешном выполнении pthread_create() возвращается 0; при ошибке
       возвращается номер ошибки, а содержимое *thread не определено.

ОШИБКИ
       EAGAIN Недостаточно ресурсов для создания другой нити.

       EAGAIN Возникло системного ограничение на количество нитей. Есть
              несколько ограничений, которые могут вызвать эту ошибку: был
              достигнут мягкий ограничитель RLIMIT_NPROC (задаётся с помощью
              setrlimit(2)), который ограничивает количество процессов и ните
              для реального ID пользователя; был достигнут ядерный системный
              ограничитель на количество процессов и нитей,
              /proc/sys/kernel/threads-max (смотрите proc(5)); был достигнуто
              максимальное количество PID, /proc/sys/kernel/pid_max (смотрите
              proc(5)).

       EINVAL Некорректные значения в attr.

       EPERM  Нет прав на изменение алгоритма планирования и параметров,
              указанных в attr.

АТРИБУТЫ
       Описание терминов данного раздела смотрите в attributes(7).

       ┌─────────────────┬──────────────────────┬──────────┐
       │Интерфейс        Атрибут              Значение │
       ├─────────────────┼──────────────────────┼──────────┤
       │pthread_create() │ Безвредность в нитях │ MT-Safe  │
       └─────────────────┴──────────────────────┴──────────┘

СООТВЕТСТВИЕ СТАНДАРТАМ
       POSIX.1-2001, POSIX.1-2008.

ЗАМЕЧАНИЯ
       Дополнительную информацию об идентификаторе нити, возвращаемом
       pthread_create() в *thread смотрите в pthread_self(3). Если не
       используются алгоритмы планирования реального времени после вызова
       pthread_create() невозможно сказать какая нить — создавшая или новая —
       будет выполняться далее первой.

       Нить может быть присоединяема (joinable) или отключённой (detached). Если
       нить присоединяема, то другая нить может вызвать pthread_join(3) для
       ожидания завершения нити и получения её кода выхода. Освобождение
       ресурсов обратно в систему у завершённой присоединяемой нити происходит
       только после её присоединения. При завершении отключённой нити, её
       ресурсы автоматически освобождаются обратно в систему: к ней невозможно
       присоединиться для получения её кода выхода. Создание отключённых нитей
       полезно в некоторых типах служебных нитей, чей код выхода не нужен
       приложению. По умолчанию новая нить создаётся в присоединяемом состоянии,
       если в attr не указано создание нити в отключённом состоянии (с помощью
       pthread_attr_setdetachstate(3)).

       В Linux/x86-32 размер стека по умолчанию для новой нити равен 2
       мегабайтам. В реализации нитей NPTL, если мягкое ограничение ресурса
       RLIMIT_STACK в момент запуска программы не равно «unlimited», то им
       задаётся размер стека по умолчанию для новых нитей. Чтобы получить размер
       стека, отличный от умолчательного при создании новой нити, можно изменить
       атрибут размера стека в аргументе attr с помощью
       pthread_attr_setstacksize(3).

ДЕФЕКТЫ
       В устаревшей реализации LinuxThreads каждая нить процесса имеет свой
       неодинаковый ID процесса. Это нарушает спецификацию нитей POSIX и
       является источником многих других несоответствий стандарту; смотрите
       pthreads(7).

ПРИМЕР
       Представленная ниже программа показывает использование pthread_create(),
       а также других функций программного интерфейса pthreads.

       В этом сеансе в системе с реализацией нитей NPTL размер стека по
       умолчанию берётся из значения ограничения ресурса на «размер стека»:

           $ ulimit -s
           8192            # ограничение на размер стека 8 МБ (0x800000 байт)
           $ ./a.out hola salut servus
           Нить 1: вершина стека около 0xb7dd03b8; argv_string=hola
           Нить 2: вершина стека около 0xb75cf3b8; argv_string=salut
           Нить 3: вершина стека около 0xb6dce3b8; argv_string=servus
           Присоединение нити 1; получено значение возврата HOLA
           Присоединение нити 2; получено значение возврата SALUT
           Присоединение нити 3; получено значение возврата SERVUS

       В этом сеансе программа явно устанавливает размер стека в 1 МБ (с помощью
       pthread_attr_setstacksize(3)) для создаваемых нитей:

           $ ./a.out -s 0x100000 hola salut servus
           Нить 1: вершина стека около 0xb7d723b8; argv_string=hola
           Нить 2: вершина стека около 0xb7c713b8; argv_string=salut
           Нить 3: вершина стека около 0xb7b703b8; argv_string=servus
           Присоединение нити 1; получено значение возврата HOLA
           Присоединение нити 2; получено значение возврата SALUT
           Присоединение нити 3; получено значение возврата SERVUS

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

       #include <pthread.h>
       #include <string.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <unistd.h>
       #include <errno.h>
       #include <ctype.h>

       #define handle_error_en(en, msg) \
               do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

       #define handle_error(msg) \
               do { perror(msg); exit(EXIT_FAILURE); } while (0)

       struct thread_info {    /* используется как аргумент thread_start() */
           pthread_t thread_id;        /* ID, полученный от pthread_create() */
           int       thread_num;       /* номер нити, определяемый
                                          приложением */
           char     *argv_string;      /* аргумент из командой строки */
       };

       /* Начальная функция нити: показывает адрес около вершины нашего стека,
          и возвращает копию argv_string заглавными буквами */

       static void *
       thread_start(void *arg)
       {
           struct thread_info *tinfo = arg;
           char *uargv, *p;

           printf("Нить %d: вершина стека около %p; argv_string=%s\n",
                   tinfo->thread_num, &p, tinfo->argv_string);

           uargv = strdup(tinfo->argv_string);
           if (uargv == NULL)
               handle_error("strdup");

           for (p = uargv; *p != '\0'; p++)
               *p = toupper(*p);

           return uargv;
       }

       int
       main(int argc, char *argv[])
       {
           int s, tnum, opt, num_threads;
           struct thread_info *tinfo;
           pthread_attr_t attr;
           int stack_size;
           void *res;

           /* Параметром «-s» определяется размер стека в наших нитях */

           stack_size = -1;
           while ((opt = getopt(argc, argv, "s:")) != -1) {
               switch (opt) {
               case 's':
                   stack_size = strtoul(optarg, NULL, 0);
                   break;

               default:
                   fprintf(stderr, "Исп.: %s [-s размер стека] арг...\n",
                           argv[0]);
                   exit(EXIT_FAILURE);
               }
           }

           num_threads = argc - optind;

           /* инициализация атрибутов создания нити */

           s = pthread_attr_init(&attr);
           if (s != 0)
               handle_error_en(s, "pthread_attr_init");

           if (stack_size > 0) {
               s = pthread_attr_setstacksize(&attr, stack_size);
               if (s != 0)
                   handle_error_en(s, "pthread_attr_setstacksize");
           }

           /* выделение памяти для аргументов pthread_create() */

           tinfo = calloc(num_threads, sizeof(struct thread_info));
           if (tinfo == NULL)
               handle_error("calloc");

           /* создание по одной нити на каждый аргумент командной строки */

           for (tnum = 0; tnum < num_threads; tnum++) {
               tinfo[tnum].thread_num = tnum + 1;
               tinfo[tnum].argv_string = argv[optind + tnum];

               /* вызов pthread_create() сохраняет ID нити в
                  соответствующий элемент tinfo[] */

               s = pthread_create(&tinfo[tnum].thread_id, &attr,
                                  &thread_start, &tinfo[tnum]);
               if (s != 0)
                   handle_error_en(s, "pthread_create");
           }

           /* уничтожение объекта атрибутов нити, так как он
              больше не нужен */

           s = pthread_attr_destroy(&attr);
           if (s != 0)
               handle_error_en(s, "pthread_attr_destroy");

           /* теперь присоединяем каждую нить и показываем значение,
              возвращённое ею */

           for (tnum = 0; tnum < num_threads; tnum++) {
               s = pthread_join(tinfo[tnum].thread_id, &res);
               if (s != 0)
                   handle_error_en(s, "pthread_join");

               printf("Присоединение нити %d; получено значение возврата %s\n",
                       tinfo[tnum].thread_num, (char *) res);
               free(res);      /* освобождаем память, выделенную нитью */
           }

           free(tinfo);
           exit(EXIT_SUCCESS);
       }

СМОТРИТЕ ТАКЖЕ
       getrlimit(2), pthread_attr_init(3), pthread_cancel(3), pthread_detach(3),
       pthread_equal(3), pthread_exit(3), pthread_getattr_np(3),
       pthread_join(3), pthread_self(3), pthreads(7)



Linux                              2015-07-23                  PTHREAD_CREATE(3)