После создания поток начинает выполнять потоковую функцию. Это самая обычная функция, которая содержит код потока. По завершении функции поток уничтожается. В Linux потоковые функции принимают единственный параметр типа
void*
и возвращают значение аналогичного типа. Этот параметр называется аргументом потока. Через него программы могут передавать данные потокам. Аналогичным образом через возвращаемое значение программы принимают данные от потоков.
Функция
pthread_create
создает новый поток. Ей передаются следующие параметры.
■ Указатель на переменную типа
pthread_t
, в которой сохраняется идентификатор нового потока.
■ Указатель на объект атрибутов потока. Этот объект определяет взаимодействие потока с остальной частью программы. Если задать его равным
NULL
, поток будет создан со стандартными атрибутами. Подробнее данная тема обсуждается в разделе 4.1.5, "Атрибуты потоков".
■ Указатель на потоковую функцию. Функция имеет следующий тип:
void* (*)(void*)
■ Значение аргумента потока (тип
void*
). Данное значение без каких-либо изменений передается потоковой функции.
Функция
pthread_create
немедленно завершается, и родительский поток переходит к выполнению инструкции, следующей после вызова функции. Тем временем новый поток начинает выполнять потоковую функцию. ОС Linux планирует работу обоих потоков асинхронно, поэтому программа не должна рассчитывать на какую-то согласованность между ними.
Программа, представленная в листинге 4.1, создает поток, который непрерывно записывает символы 'x' в стандартный поток ошибок. После вызова функции
pthread_create
основной поток начинает делать то же самое, но вместо символов 'x' печатаются символы 'o'.
Непрерывная запись символов 'o' в поток stderr. */
while (1)
fputc('o', stderr);
return 0;
}
Компиляция и компоновка программы осуществляются следующим образом:
% cc -o thread-create thread-create.c -lpthread
Запустите программу, и вы увидите, что символы 'x' и 'o' чередуются самым непредсказуемым образом.
При нормальных обстоятельствах поток завершается одним из двух способов. Один из них — выход из потоковой функции. Возвращаемое ею значение считается значением, передаваемым из потока в программу. Второй способ— вызов специальной функции
pthread_exit
. Это может быть сделано как в потоковой функции, так и в любой другой функции, явно или неявно вызываемой из нее. Аргумент функции
pthread_exit
является значением, которое возвращается потоком.
4.1.1. Передача данных потоку
Потоковый аргумент — это удобное средство передачи данных потокам. Но поскольку его тип
void*
, данные содержатся не в самом аргументе. Он лишь должен указывать на какую-то структуру или массив. Лучше всего создать для каждой потоковой функции собственную структуру, в которой определялись бы "параметры", ожидаемые потоковой функцией.
Благодаря наличию потокового аргумента появляется возможность использовать одну и ту же потоковую функцию с разными потоками. Все они будут выполнять один и тот же код, но с разными данными.
Программа, приведенная в листинге 4.2, напоминает предыдущий пример. На этот раз создаются два потока: один отображает символы 'x', а другой — символы 'o'. Чтобы вывод на экран не длился бесконечно, потокам передается дополнительный аргумент, определяющий, сколько раз следует отобразить символ. Одна и та же функция
char_print
эксплуатируется обоими потоками, но каждый из них конфигурируется независимо с помощью структуры
char_print_parms
.
Листинг 4.2. (thread-create2.c) Создание двух потоков
#include <pthread.h>
#include <stdio.h>
/* Параметры для функции char_print. */
struct char_print_parms {
/* Отображаемый символ. */
char character;
/* Сколько раз его нужно отобразить. */
int count;
};
/* Запись указанного числа символов в поток stderr. Аргумент