Чтение онлайн

ЖАНРЫ

UNIX: разработка сетевых приложений
Шрифт:

Обе функции возвращают: 0 в случае успешного выполнения, положительное значение Exxx в случае ошибки

Функция

pthread_once
обычно вызывается при вызове функции, манипулирующей собственными данными потока, но
pthread_once
использует значение переменной, на которую указывает
onceptr
, чтобы гарантировать, что функция
init
вызывается для каждого процесса только один раз.

Функция

pthread_key_create
должна вызываться только один раз для данного ключа в пределах одного процесса. Значение ключа возвращается с помощью указателя
keyptr
,
а функция – деструктор(если аргумент является непустым указателем) будет вызываться каждым потоком по завершении его выполнения, если этот поток записывал какое-либо значение, соответствующее этому ключу.

Обычно эти две функции используются следующим образом (если игнорировать возвращение ошибок):

pthread_key_t rl_key;

pthread_once_t rl_once = PTHREAD_ONCE_INIT;

void readline_destructor(void *ptr) {

free(ptr);

}

void readline_once(void) {

pthread_key_create(&rl_key, readline_destructor);

}

ssize_t readline(...) {

...

pthread_once(&rl_once, readline_once);

if ((ptr = pthread_getspecific(rl_key)) == NULL) {

ptr = Malloc(...);

pthread_setspecifiс(rl_key, ptr);

/* инициализация области памяти, на которую указывает ptr */

}

...

/* используются значения, на которые указывает ptr */

}

Каждый раз, когда вызывается функция

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 key);

Возвращает: указатель на собственные данные потока (возможно, пустой указатель)

int pthread_setspecific(pthread_key_t key, const void * value);

Возвращает: 0
в случае успешного выполнения, положительное значение Exxx в случае ошибки

Обратите внимание на то, что аргументом функции

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
.

Структура Rline

14-18
Наша структура
Rline
содержит три переменные, которые, будучи объявленными как статические (
static
) в листинге 3.12, привели к возникновению описанных далее проблем. Такая структура динамически выделяется в памяти для каждого потока, а по завершении выполнения этого потока она освобождается функцией-деструктором.

В листинге 26.6 показана сама функция

readline
, а также функция
my_read
, которую она вызывает. Этот листинг является модификацией листинга 3.12.

Поделиться с друзьями: