POSIX Threads
POSIX Threads — стандарт POSIX-реализации потоков (нитей) выполнения. Стандарт POSIX.1c, Threads extensions (IEEE Std 1003.1c-1995) определяет API для управления потоками, их синхронизации и планирования.
Реализации данного API существуют для большого числа UNIX-подобных ОС (GNU/Linux, Solaris, FreeBSD, OpenBSD, NetBSD, OS X), а также для Microsoft Windows и других ОС.
Библиотеки, реализующие этот стандарт (и функции этого стандарта), обычно называются Pthreads (функции имеют приставку «pthread_»).
Основные функции стандарта
Pthreads определяет набор типов и функций на языке программирования Си. Заголовочный файл — pthread.h.
- Типы данных:
- pthread_t: дескриптор потока;
- pthread_attr_t: перечень атрибутов потока;
- pthread_barrier_t: барьер;
- pthread_barrierattr_t: атрибуты барьера;
- pthread_cond_t: условная переменная;
- pthread_condattr_t: атрибуты условной переменной;
- pthread_key_t: данные, специфичные для потока;
- pthread_mutex_t: мьютекс;
- pthread_mutexattr_t: атрибуты мьютекса;
- pthread_rwlock_t: мьютекс с возможностью эксклюзивной блокировки;
- pthread_rwlockattr_t: атрибуты этого мьютекса;
- pthread_spinlock_t: спинлок;
- Функции управления потоками:
- pthread_create(): создание потока.
- pthread_exit(): завершение потока (должна вызываться функцией потока при завершении).
- pthread_cancel(): отмена потока.
- pthread_join(): подключиться к другому потоку и ожидать его завершения; поток, к которому необходимо подключиться, должен быть создан с возможностью подключения (PTHREAD_CREATE_JOINABLE).
- pthread_detach(): отключиться от потока, сделав его при этом отдельным (PTHREAD_CREATE_DETACHED).
- pthread_attr_init(): инициализировать структуру атрибутов потока.
- pthread_attr_setdetachstate(): указывает параметр "отделимости" потока (detach state), который говорит о возможности подключения к нему (при помощи pthread_join) других потоков (значение PTHREAD_CREATE_JOINABLE) для ожидания окончания или о запрете подключения (значение PTHREAD_CREATE_DETACHED); ресурсы отдельного потока (PTHREAD_CREATE_DETACHED) при завершении автоматически освобождаются и возвращаются системе.
- pthread_attr_destroy(): освободить память от структуры атрибутов потока (уничтожить дескриптор).
- Функции синхронизации потоков:
- pthread_mutex_init(), pthread_mutex_destroy(), pthread_mutex_lock(), pthread_mutex_trylock(), pthread_mutex_unlock(): с помощью мьютексов.
- pthread_cond_init(), pthread_cond_signal(), pthread_cond_wait(): с помощью условных переменных.
Пример
Пример использования потоков на языке C:
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <pthread.h> void wait_thread (void); void* thread_func (void*); int main (int argc, char *argv[], char *envp[]) { pthread_t thread; if (pthread_create(&thread,NULL,thread_func,NULL)) return EXIT_FAILURE; for (unsigned int i = 0; i < 20; i++) { puts("a"); wait_thread(); } if (pthread_join(thread,NULL)) return EXIT_FAILURE; return EXIT_SUCCESS; } void wait_thread (void) { time_t start_time = time(NULL); while(time(NULL) == start_time) {} } void* thread_func (void* vptr_args) { for (unsigned int i = 0; i < 20; i++) { fputs("b\n",stderr); wait_thread(); } return NULL; }
Пример использования потоков на языке C++:
#include <cstdlib> #include <iostream> #include <memory> #include <unistd.h> #include <pthread.h> class Thread { public: int start () { return pthread_create( &_ThreadId, nullptr, Thread::thread_func, this ); } int wait () { return pthread_join( _ThreadId, nullptr ); } protected: Thread() = default; Thread(const Thread&); virtual ~Thread () = default; virtual void run () = 0; static void* thread_func(void* d) { (static_cast <Thread*>(d))->run(); return nullptr; } private: pthread_t _ThreadId; }; class TestingThread : public Thread { public: TestingThread (const char* pcszText) : _pcszText( pcszText ) {} virtual void run () { for (unsigned int i = 0; i < 20; i++, usleep(1000)) std::cout << _pcszText << std::endl; } protected: const char* _pcszText; }; int main (int argc, char *argv[], char *envp[]) { TestingThread ThreadA("a"); TestingThread ThreadB("b"); return ThreadA.start() || ThreadB.start() || ThreadA.wait() || ThreadB.wait() ? EXIT_FAILURE : EXIT_SUCCESS; }
Представленные программы используют два потока, печатающих в консоль сообщения, один, печатающий 'a', второй — 'b'. Вывод сообщений смешивается в результате переключения выполнения между потоками или одновременном выполнении на мультипроцессорных системах.
Отличие состоит в том, что программа на C создаёт один новый поток для печати 'b', а основной поток печатает 'a'. Основной поток (после печати 'aaaaa….') ждёт завершения дочернего потока.
Программа на C++ создаёт два новых потока, один печатает 'a', второй, соответственно, — 'b'. Основной поток ждёт завершения обоих дочерних потоков.
См. также
- Native POSIX Thread Library (NPTL)
- GNU Portable Threads
- Список многопоточных библиотек C++
Ссылки
- Статья «Объясняя потоки POSIX», Даниэля Роббинса (основателя проекта Gentoo) (англ.)
- Интервью «10 вопросов Девиду Бутенхофу о параллельном программировании и потоках POSIX» с Майклом Суиссом (англ.)
- The Open Group Base Specifications Issue 6, IEEE Std 1003.1 (англ.)
- Pthreads Presentation at 2007 OSCON (O’Reilly Open Source Convention) by Adrien Lamothe. An overview of Pthreads with current trends Архивная копия от 24 апреля 2013 на Wayback Machine (англ.)
- Установка библиотеки pthread.h в среде Visual Studio