■ Указатель на потоковую функцию. Функция имеет следующий тип:
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. Аргумент
PARAMETERS является указателем на структуру char_print_parms. */
Но постойте! Приведенная программа имеет серьезную ошибку. Основной поток (выполняющий функцию
main
) создает структуры
thread1_args
и
thread2_args
в виде локальных переменных, а затем передает указатели на них дочерним потокам. Что мешает Linux распланировать работу потоков так, чтобы функция
main
завершилась до того, как будут завершены другие два потока? Ничего! Но если это произойдет, структуры окажутся удаленными из памяти, хотя оба потока все еще ссылаются на них.