Вход/Регистрация
UNIX: разработка сетевых приложений
вернуться

Стивенс Уильям Ричард

Шрифт:

Мы будем использовать функцию

pthread_once
, чтобы гарантировать, что функция
pthread_key_create
вызывается только первым потоком, вызвавшим функцию
readline
.

3. Функция

readline
вызывает функцию
pthread_getspecific
, чтобы получить значение
pkey[1]
(«указатель» на рис. 26.3 для ключа, имеющего значение 1) для данного потока, но эта функция возвращает пустой указатель. Тогда функция
readline
вызывает функцию
malloc
для выделения памяти, которая необходима для хранения информации о каждом потоке при последовательных вызовах функции
readline
. Функция
readline
инициализирует эти области памяти по мере надобности и вызывает функцию
pthread_setspecific
, чтобы установить указатель собственных данных потока (
pkey[1]
), соответствующий данному ключу, на только что выделенную область памяти. Мы показываем этот процесс на рис. 26.4, предполагая, что вызывающий поток — это поток с номером 0 в данном процессе.

Рис. 26.4. Соответствие между областью памяти, выделенной функцией malloc, и указателем собственных данных потока

На этом рисунке мы отмечаем, что структура Pthread поддерживается системой (вероятно, библиотекой потоков), но фактически собственные данные потока, которые мы размещаем в памяти с помощью функции

malloc
, поддерживаются нашей функцией (в данном случае
readline
). Все, что делает функция
pthread_setspecific
, — это установка указателя для данного ключа в структуре Pthread на выделенную область памяти. Аналогично, действие функции
pthread_getspecific
сводится к возвращению этого указателя.

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 <pthread.h>

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 */

}

  • Читать дальше
  • 1
  • ...
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: