Каждый раз, когда вызывается функция
readline
, она вызывает функцию
pthread_once
. Эта функция использует значение, на которое указывает ее аргумент-указатель
onceptr
(содержащийся в переменной
rl_once
), чтобы удостовериться, что функция
init
вызывается только один раз. Функция инициализации
readline_once
создает ключ для собственных данных потока, который хранится в
rl_key
и который функция
readline
затем использует в вызовах функций
pthread_getspecific
и
pthread_setspecific
.Функции
pthread_getspecific
и
pthread_setspecific
используются для того, чтобы получать и задавать значение, ассоциированное с данным ключом. Это значение представляет собой тот указатель, который показан на рис. 26.3. На что указывает этот указатель — зависит от приложения, но обычно он указывает на динамически выделяемый участок памяти.#include pthread.h
void *pthread_getspecific(pthread_key_t
int pthread_setspecific(pthread_key_t
Обратите внимание на то, что аргументом функции
pthread_key_create
является указатель на ключ (поскольку эта функция хранит значение, присвоенное ключу), в то время как аргументами функций
get
и
set
являются сами ключи (которые, скорее всего, представляют собой небольшие целые числа, как уже говорилось).Пример: функция readline, использующая собственные данные потока
В этом разделе мы приводим полный пример использования собственных данных потока, преобразуя оптимизированную версию функции
readline
из листинга 3.12 к виду, безопасному в многопоточной среде, не изменяя последовательность вызовов.В листинге 26.5 показана первая часть функции: переменные
pthread_key_t
и
pthread_once_t
, функции
readline_destructor
и
readline_once
и наша структура
Rline
, которая содержит всю информацию, нужную нам для каждого потока.Листинг 26.5
. Первая часть функции readline, безопасной в многопоточной среде//threads/readline.c
1 #include "unpthread.h"
2 static pthread_key_t rl_key;
3 static pthread_once_t rl_once = PTHREAD_ONCE_INIT;
4 static void
5 readline_destructor(void *ptr)
6 {
7 free(ptr);
8 }
9 static void
10 readline_once(void)
11 {
12 Pthread_key_create(rl_key, readline_destructor);
13 }
14 typedef struct {
15 int rl_cnt; /* инициализируется нулем */
16 char *rl_bufptr; /* инициализируется значением rl_buf */
17 char rl_buf[MAXLINE];
18 } Rline;
4-8
9-13
pthread_once
и создает ключ, который затем используется в функции
readline
.14-18
Rline
содержит три переменные, которые, будучи объявленными как статические (
static
) в листинге 3.12, привели к возникновению описанных далее проблем. Такая структура динамически выделяется в памяти для каждого потока, а по завершении выполнения этого потока она освобождается функцией-деструктором.В листинге 26.6 показана сама функция
readline
, а также функция
my_read
, которую она вызывает. Этот листинг является модификацией листинга 3.12.Листинг 26.6
. Вторая часть функции readline, безопасной в многопоточной среде//threads/readline.c
19 static ssize_t
20 my_read(Rline *tsd, int fd, char *ptr)
21 {
22 if (tsd-rl_cnt = 0) {
23 again:
24 if ((tsd-rl_cnt = read(fd, tsd-rl_buf, MAXLINE)) 0) {
25 if (errno == EINTR)
26 goto again;
27 return (-1);
28 } else if (tsd-rl_cnt == 0)
29 return (0);