Потоки (threads) и многопоточное выполнение программ (multi-threading)
Потоки POSIX (Pthreads)
В качестве конкретной модели многопоточности рассмотрим потоки POSIX (напомним, что данная аббревиатура расшифровывается как Portable Operating Systems Interface of uniX kind – стандарты для переносимых ОС типа UNIX). Многопоточность в POSIX специфицирована стандартом IEEE 1003.1c, который описывает API для создания и синхронизации потоков. Отметим, что POSIX-стандарт API определяет лишь требуемое поведение библиотеки потоков. Реализация потоков оставляется на усмотрение авторов конкретной POSIX-совместимой библиотеки. POSIX-потоки распространены в ОС типа UNIX, а также поддержаны, с целью совместимости программ, во многих других ОС, например, Solaris и Windows NT.
Стандарт POSIX определяет два основных типа данных для потоков: pthread_t – дескриптор потока ; pthread_attr_t – набор атрибутов потока.
Стандарт POSIX специфицирует следующий набор функций для управления потоками:
- pthread_create(): создание потока
- pthread_exit():завершение потока (должна вызываться функцией потока при завершении)
- pthread_cancel():отмена потока
- pthread_join():заблокировать выполнение потока до прекращения другого потока, указанного в вызове функции
- pthread_detach():освободить ресурсы занимаемые потоком (если поток выполняется, то освобождение ресурсов произойдёт после его завершения)
- pthread_attr_init():инициализировать структуру атрибутов потока
- pthread_attr_setdetachstate():указать системе, что после завершения потока она может автоматически освободить ресурсы, занимаемые потоком
- pthread_attr_destroy():освободить память от структуры атрибутов потока (уничтожить дескриптор).
Имеются следующие примитивы синхронизации POSIX-потоков с помощью мьютексов (mutexes) – аналогов семафоров – и условных переменных (conditional variables) – оба эти типа объектов для синхронизации подробно рассмотрены позже в данном курсе:
- - pthread_mutex_init() – создание мьютекса;
- - pthread_mutex_destroy() – уничтожение мьютекса;
- - pthread_mutex_lock() – закрытие мьютекса;
- - pthread_mutex_trylock() – пробное закрытие мьютекса (если он уже закрыт, вызов игнорируется, и поток не блокируется);
- - pthread_mutex_unlock() – открытие мьютекса;
- - pthread_cond_init() – создание условной переменной;
- - pthread_cond_signal() – разблокировка условной переменной;
- - pthread_cond_wait() – ожидание по условной переменной.
Рассмотрим пример использования POSIX-потоков на языке Си.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
static void wait_thread(void)
{
time_t start_time = time(NULL);
while (time(NULL) == start_time)
{
// никаких действий, кроме занятия процессора на время до 1 с.
}
}
static void *thread_func(void *vptr_args)
{ int i;
for (i = 0; i < 20; i++) {
fputs(" b\n", stderr);
wait_thread();
}
return NULL;
}
int main(void)
{ int i;
pthread_t thread;
if (pthread_create(&thread, NULL, thread_func, NULL) != 0) {
return EXIT_FAILURE;
}
for (i = 0; i < 20; i++) {
puts("a");
wait_thread();
}
if (pthread_join(thread, NULL) != 0) {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}Пример иллюстрирует параллельное выполнение основного потока, выдающего в стандартный вывод последовательность букв "a", и дочернего потока, выдающего в стандартный поток ошибок (stderr) последовательность букв "b". Обратите внимание на особенности создания потока (pthread_create), указания его тела (исполняемой процедуры потока thread_func) и ожидания завершения дочернего потока (pthread_join).
Потоки и процессы в Solaris
В ОС Solaris, как уже было отмечено, используется модель потоков много / много. Кроме того, в системе используется также уже известное нам понятие облегченный процесс (lightweight process) промежуточное между концепцией пользовательского потока и системного потока. Таким образом, в ОС Solaris каждый пользовательский поток отображается в свой облегченный процесс, который, в свою очередь, отображается в поток ядра; последний может исполняться на любом процессоре (или ядре процессора) компьютерной системы. Схема организации потоков в Solaris изображена на рис. 10.5.
На рис. 10.6 изображена схема организации процесса в ОС Solaris.
На схеме видно, что каждый процесс содержит, кроме стандартной информации блока управления процессом, также список всех своих облегченных процессов для управления ими.


