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

на главную - закладки

Жанры

Программирование для Linux. Профессиональный подход

Самьюэл Алекс

Шрифт:

 if (account_balances(from_acct) < dollars)

return 1;

 /* Начало критической секции. */

 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_cancel_state);

 /* переводим деньги. */

 account_balances[to_acct] += dollars;

 account_balances[from_acct] -= dollars;

 /* Конец критической секции. */

 pthread_setcancelstate(old_cancel_state, NULL);

 return 0;

}

Обратите

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

4.2.3. Когда необходимо отменять поток

В общем случае не рекомендуется отменять поток, если его можно просто завершить. Лучше всего каким-то образом просигнализировать потоку о том, что он должен прекратить работу, а затем дождаться его завершения. Подробнее о способах взаимодействия с потоками речь пойдет ниже в этой главе.

4.3. Потоковые данные

В отличие от процессов, все потоки программы делят общее адресное пространство. Это означает, что если один поток модифицирует ячейку памяти (например, глобальную переменную), то это изменение отразится на всех остальных потоках. Таким образом, потоки могут работать с одними и теми же данными, не используя механизмы межзадачного взаимодействия (рассматриваются в главе 5, "Взаимодействие процессов").

Тем не менее у каждого потока — свой собственный стек вызова. Это позволяет всем потокам выполнять разный код, а также вызывать функции традиционным способом. При каждом вызове функции в любом потоке создается отдельный набор локальных переменных, которые сохраняются в стеке этого потока.

Иногда все же требуется продублировать определенную переменную, чтобы у каждого потока была ее собственная копия. С этой целью операционная система Linux предоставляет потокам область потоковых данных. Переменные, сохраняемые в этой области, дублируются для каждого потока, что позволяет потокам свободно работать с ними, не мешая друг другу. Доступ к потоковым данным нельзя получить с помощью ссылок на обычные переменные, ведь у потоков общее адресное пространство. В Linux имеются специальные функции для чтения и записи значений, хранящихся в области потоковых данных.

Можно создать сколько угодно потоковых переменных, при этом все они должны иметь тип

void*
. Ссылка на каждую переменную осуществляется по ключу. Для создания нового ключа, т.е. новой переменной, предназначена функция
pthread_key_create
. Первым ее аргументом является указатель на переменную типа
pthread_key_t
. В нее будет записано значение ключа, посредством которого любой поток сможет обращаться к своей копии данных. Второй аргумент — это указатель на функцию очистки ключа. Она будет автоматически вызываться при уничтожении потока; ей передается значение ключа, соответствующее данному потоку. Это очень удобно, так как функция очистки вызывается даже в случае отмены потока в произвольной точке. Если потоковая переменная равна
NULL
, функция очистки не вызывается. Если же такая функция не нужна, задайте в качестве второго параметра функции
pthread_key_create
значение
NULL
.

После того как ключ создан, каждый поток может назначать ему собственное значение, вызывая функцию

pthread_setspecific
. Ее первый аргумент — это ключ, а второй — требуемое значение типа
void*
. Для чтения потоковых переменных предназначена функция
pthread_getspecific
, единственным аргументом которой является ключ.

Предположим, имеется приложение, распределяющее задачу между несколькими потоками. В целях аудита за каждым потоком закреплен отдельный журнальный файл, куда записываются сообщения о ходе выполнения поставленной задачи. Область потоковых данных — удобное место для хранения указателя на журнальный файл каждого потока.

В листинге 4.7 показано, как осуществить задуманное. Для хранения файлового указателя в функции

main
создается ключ, запоминаемый в переменной
thread_log_key
. Эта переменная является глобальной, поэтому она доступна всем потокам. Когда поток начинает выполнять свою потоковую функцию, он открывает журнальный файл и сохраняет указатель на него в своем ключе. Позднее любой поток может вызвать функцию
write_to_thread_log
, чтобы записать сообщение в свой журнальный файл. Эта функция извлекает из области потоковых данных указатель на журнальный файл и помещает в файл требуемое сообщение.

Листинг 4.7. (tsd.c) Создание отдельного журнального файла для каждого потока с помощью области потоковых данных

#include <malloc.h>

#include <pthread.h>

#include <stdio.h>

/* Ключ, связывающий указатель журнального файла с каждым

потоком. */

static pthread_key_t thread_log_key;

/* Запись параметра MESSAGE в журнальный файл текущего потока. */

void write_to_thread_log(const char* message) {

 FILE* thread_log =

(FILE*)pthread_getspecific(thread_log_key);

 fprintf(thread_log, "%s\n", message);

}

/* Закрытие журнального файла, на который указывает параметр

THREAD_LOG. */

void close_thread_log(void* thread_log) {

 fclose((FILE*)thread_log);

}

void* thread_function(void* args) {

 char thread_log_filename[20];

 FILE* thread_log;

 /* Создание имени журнального файла для текущего потока. */

 sprintf(thread_log_filename, "thread%d.log",

(int)pthread_self);

 /* Открытие журнального файла. */

 thread_log = fopen(thread_log_filename, "w");

 /* Сохранение указателя файла в области потоковых данных,

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

Инцел на службе демоницы 1 и 2: Секса будет много

Блум М.
Инцел на службе демоницы
Фантастика:
фэнтези
5.25
рейтинг книги
Инцел на службе демоницы 1 и 2: Секса будет много

Весь цикл «Десантник на престоле». Шесть книг

Ланцов Михаил Алексеевич
Десантник на престоле
Фантастика:
альтернативная история
8.38
рейтинг книги
Весь цикл «Десантник на престоле». Шесть книг

Предатель. Цена ошибки

Кучер Ая
Измена
Любовные романы:
современные любовные романы
5.75
рейтинг книги
Предатель. Цена ошибки

Жандарм 2

Семин Никита
2. Жандарм
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Жандарм 2

Прогрессор поневоле

Распопов Дмитрий Викторович
2. Фараон
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Прогрессор поневоле

Всемирная энциклопедия афоризмов. Собрание мудрости всех народов и времен

Агеева Елена А.
Документальная литература:
публицистика
5.40
рейтинг книги
Всемирная энциклопедия афоризмов. Собрание мудрости всех народов и времен

Истребитель. Ас из будущего

Корчевский Юрий Григорьевич
Фантастика:
боевая фантастика
попаданцы
альтернативная история
5.25
рейтинг книги
Истребитель. Ас из будущего

Очешуеть! Я - жена дракона?!

Амеличева Елена
Фантастика:
юмористическая фантастика
5.43
рейтинг книги
Очешуеть! Я - жена дракона?!

Отмороженный 4.0

Гарцевич Евгений Александрович
4. Отмороженный
Фантастика:
боевая фантастика
постапокалипсис
рпг
5.00
рейтинг книги
Отмороженный 4.0

Треугольная шляпа. Пепита Хименес. Донья Перфекта. Кровь и песок.

Бласко Висенте Ибаньес
65. Библиотека всемирной литературы
Проза:
классическая проза
5.00
рейтинг книги
Треугольная шляпа.
Пепита Хименес.
Донья Перфекта.
Кровь и песок.

Измена. Жизнь заново

Верди Алиса
1. Измены
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Жизнь заново

Три `Д` для миллиардера. Свадебный салон

Тоцка Тала
Любовные романы:
современные любовные романы
короткие любовные романы
7.14
рейтинг книги
Три `Д` для миллиардера. Свадебный салон

Бастард Императора. Том 5

Орлов Андрей Юрьевич
5. Бастард Императора
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 5

Идеальный мир для Лекаря 21

Сапфир Олег
21. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 21