Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
4. Другой поток, например поток с номером n
, вызывает функцию readline
, возможно, в тот момент, когда поток с номером 0 все еще находится в стадии выполнения функции readline
.
Функция readline
вызывает функцию pthread_once
, чтобы инициализировать ключ этого элемента собственных данных, но так как эта функция уже была однажды вызвана, то больше она не выполняется.
5. Функция readline
вызывает функцию pthread_getspecific
для получения значения указателя pkey[1]
для данного потока, но возвращается пустой указатель. Тогда поток вызывает функцию malloc
и функцию pthread_setspecific
, как и в случае с потоком номер 0, инициализируя элемент собственных данных потока, соответствующий этому ключу (1). Этот процесс иллюстрирует рис. 26.5.

Рис. 26.5. Структуры данных после того, как поток n инициализировал свои собственные данные
6. Поток номер n продолжает выполнять функцию readline
, используя и модифицируя свои собственные данные.
Один вопрос, который мы пока не рассмотрели, заключается в следующем: что происходит, когда поток завершает свое выполнение? Если поток вызвал функцию readline
, эта функция выделила в памяти область, которая должна быть освобождена по завершении выполнения потока. Для этого используется указатель-деструктор , показанный на рис. 26.2. Когда поток, создающий элемент собственных данных, вызывает функцию pthread_key_create
, одним из аргументов этой функции является указатель на функцию-деструктор . Когда выполнение потока завершается, система перебирает массив pkey
для данного потока, вызывая соответствующую функцию-деструктор для каждого непустого указателя pkey
. Под «соответствующим деструктором» мы понимаем указатель на функцию, хранящийся в массиве Key
с рис. 26.2. Таким образом осуществляется освобождение памяти, занимаемой собственными данными потока, когда выполнение потока завершается.
Первые две функции, которые обычно вызываются при работе с собственными данными потока, — это pthread_once
и pthread_key_create
.
#include
int pthread_once(pthread_once_t * onceptr , void (* init )(void));
int pthread_key_create(pthread_key_t * keyptr , void (* destructor )(void * value ));
Обе функции возвращают: 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
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
.
Интервал:
Закладка: