Открыть сервис

Pthreads

Pthreads (сокращение от англ. POSIX Threads) — это стандарт POSIX (IEEE 1003.1c), определяющий интерфейс (API) для многопоточного программирования на языках C и C++. Pthreads предоставляет набор функций, типов данных и атрибутов для создания, синхронизации и управления потоками выполнения (нитями) в рамках одного процесса. Стандарт обеспечивает переносимость многопоточного кода между различными операционными системами, поддерживающими POSIX, включая большинство Unix-подобных систем (Linux, FreeBSD, macOS) и, в урезанном виде, Windows (через сторонние библиотеки).

История

Разработка стандарта Pthreads началась в середине 1990-х годов как часть расширения стандарта POSIX. До этого многопоточность в Unix-системах реализовывалась нестандартными, проприетарными API (например, threads от Sun Microsystems или DCE Threads). Основной целью создания Pthreads было унификация интерфейсов для обеспечения переносимости приложений между разными реализациями Unix.

В 1995 году стандарт POSIX.1c (Threads Extensions) был принят как часть IEEE Std 1003.1-1996. Позже он вошёл в единый стандарт POSIX (IEEE Std 1003.1-2001, известный как POSIX.1-2001). С тех пор Pthreads является обязательным компонентом для сертификации системы как POSIX-совместимой. Наиболее полная и стабильная реализация Pthreads — NPTL (Native POSIX Thread Library), разработанная компанией Red Hat и включённая в ядро Linux начиная с версии 2.6. NPTL пришла на смену более старой библиотеке LinuxThreads, которая имела ряд ограничений (например, несоответствие стандарту в части сигналов и идентификаторов потоков).

Основные концепции

Поток выполнения (thread)

Поток — это наименьшая единица обработки, которой операционная система может выделять процессорное время. В рамках одного процесса все потоки разделяют общее адресное пространство (код, данные, кучу), но имеют собственный стек, регистры и локальные переменные. Это позволяет потокам эффективно обмениваться данными без использования механизмов межпроцессного взаимодействия (IPC), таких как каналы или очереди сообщений.

Идентификатор потока (pthread_t)

Каждый поток в системе Pthreads имеет уникальный идентификатор типа pthread_t. Этот тип может быть целым числом, указателем или структурой в зависимости от реализации. Идентификатор используется для обращения к потоку при его создании, ожидании завершения или изменении его атрибутов.

Атрибуты потока (pthread_attr_t)

Перед созданием потока можно задать его атрибуты: размер стека, политику планирования, приоритет, состояние отсоединения (detached state) и другие. Атрибуты хранятся в объекте типа pthread_attr_t, который инициализируется функцией pthread_attr_init() и уничтожается функцией pthread_attr_destroy().

Синхронизация

Для координации доступа потоков к разделяемым ресурсам Pthreads предоставляет несколько механизмов синхронизации:

  • Мьютексы (mutex) — объекты типа pthread_mutex_t, обеспечивающие взаимное исключение. Поток, захвативший мьютекс, получает монопольный доступ к критической секции. Другие потоки блокируются до его освобождения. Поддерживаются обычные, рекурсивные, проверочные и с защитой от ошибок мьютексы.
  • Условные переменные (condition variable) — объекты типа pthread_cond_t, используемые для блокировки потока до наступления определённого условия. Поток может ждать на условной переменной, освобождая мьютекс, и быть разбуженным другим потоком, который изменил условие.
  • Барьеры (barrier) — объекты типа pthread_barrier_t, позволяющие синхронизировать группу потоков в заданной точке выполнения. Все потоки ждут, пока последний не достигнет барьера, после чего они продолжают выполнение.
  • Спин-блокировки (spinlock) — объекты типа pthread_spinlock_t, реализующие активное ожидание (busy-waiting) вместо блокировки потока. Используются в критических секциях с очень коротким временем выполнения.
  • Чтение-запись блокировки (rwlock) — объекты типа pthread_rwlock_t, позволяющие множеству потоков одновременно читать данные, но предоставляющие монопольный доступ для записи.

Основные функции API

Управление потоками

ФункцияНазначение
pthread_create()Создание нового потока. Принимает идентификатор потока, атрибуты, функцию потока и аргумент.
pthread_join()Ожидание завершения указанного потока. Возвращает возвращаемое значение функции потока.
pthread_detach()Перевод потока в отсоединённое состояние. После завершения такого потока его ресурсы автоматически освобождаются.
pthread_exit()Завершение текущего потока с возвратом указателя.
pthread_cancel()Отправка запроса на отмену выполнения потока.
pthread_self()Получение идентификатора текущего потока.
pthread_equal()Сравнение двух идентификаторов потоков.

Синхронизация

ФункцияНазначение
pthread_mutex_init(), pthread_mutex_destroy()Инициализация и уничтожение мьютекса.
pthread_mutex_lock(), pthread_mutex_trylock(), pthread_mutex_unlock()Захват, попытка захвата и освобождение мьютекса.
pthread_cond_init(), pthread_cond_destroy()Инициализация и уничтожение условной переменной.
pthread_cond_wait(), pthread_cond_signal(), pthread_cond_broadcast()Ожидание, сигнал одному потоку и сигнал всем ожидающим потокам.
pthread_barrier_init(), pthread_barrier_wait()Инициализация и ожидание на барьере.
pthread_rwlock_init(), pthread_rwlock_rdlock(), pthread_rwlock_wrlock(), pthread_rwlock_unlock()Работа с блокировками чтения-записи.

Управление атрибутами

ФункцияНазначение
pthread_attr_init(), pthread_attr_destroy()Инициализация и уничтожение объекта атрибутов.
pthread_attr_setdetachstate(), pthread_attr_getdetachstate()Установка/получение состояния отсоединения.
pthread_attr_setstacksize(), pthread_attr_getstacksize()Установка/получение размера стека потока.
pthread_attr_setschedpolicy(), pthread_attr_getschedpolicy()Установка/получение политики планирования (SCHED_FIFO, SCHED_RR, SCHED_OTHER).

Пример использования

Ниже приведён простейший пример создания и ожидания потока на языке C:

```c

include <stdio.h>

include <pthread.h>

void thread_function(void arg) { int num = (int)arg; printf("Поток получил число: %d\n", *num); return NULL; }

int main() { pthread_t thread; int value = 42;

// Создание потока if (pthread_create(&thread, NULL, thread_function, &value) != 0) { perror("pthread_create"); return 1; }

// Ожидание завершения потока if (pthread_join(thread, NULL) != 0) { perror("pthread_join"); return 1; }

printf("Главный поток завершён\n"); return 0; } ```

Компиляция такого кода в Linux выполняется с флагом -lpthread: ``bash gcc -o example example.c -lpthread ``

Преимущества и недостатки

Преимущества

  • Переносимость: код, написанный с использованием Pthreads, может быть скомпилирован и выполнен на любой POSIX-совместимой системе.
  • Эффективность: потоки внутри процесса разделяют память, что снижает накладные расходы на переключение контекста по сравнению с процессами.
  • Гибкость: широкий набор механизмов синхронизации позволяет решать различные задачи многопоточного программирования.
  • Низкоуровневость: прямой контроль над созданием, синхронизацией и завершением потоков.

Недостатки

  • Сложность: ручное управление потоками и синхронизацией требует высокой квалификации разработчика и чревато ошибками (гонки данных, взаимные блокировки, инверсия приоритетов).
  • Отсутствие встроенной поддержки в Windows: хотя существуют сторонние библиотеки (pthreads-w32), нативная реализация Pthreads в Windows отсутствует.
  • Ограниченная масштабируемость: при большом количестве потоков (сотни и тысячи) накладные расходы на переключение контекста и синхронизацию могут стать значительными. Для таких сценариев часто используются более лёгкие модели (например, корутины или фьючерсы).
  • Небезопасность: отсутствие встроенной защиты от гонок данных — программист должен самостоятельно обеспечивать корректную синхронизацию.

Альтернативы и современные подходы

В современных C++ (начиная с C++11) появился стандартный многопоточный API (std::thread, std::mutex, std::condition_variable), который является более высокоуровневой обёрткой над Pthreads и обеспечивает лучшую переносимость между платформами. В других языках программирования (Java, Python, Go) многопоточность реализуется через собственные библиотеки и модели (например, горутины в Go). Тем не менее, Pthreads остаётся основным низкоуровневым стандартом для многопоточного программирования в Unix-среде и широко используется в системном программировании, серверных приложениях, базах данных и высоконагруженных системах.

Источники

  • IEEE Std 1003.1-2017 (POSIX.1-2017). System Interfaces: Threads.
  • Б. Керниган, Р. Пайк. «Практика программирования». Глава 6 (Многопоточность).
  • W. Richard Stevens, Stephen A. Rago. «Advanced Programming in the UNIX Environment». Глава 11 (Threads).
  • Документация библиотеки NPTL (Native POSIX Thread Library) — проект Red Hat.
  • Материалы курса «Многопоточное программирование» (Computer Science Center, 2020).

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →