- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания UNIX: взаимодействие процессов - Уильям Стивенс
Шрифт:
Интервал:
Закладка:
//my_rwlock/pthread_rwlock_tryrdlock.с
1 #include "unpipc.h"
2 #include "pthread_rwlock.h"
3 int
4 pthread_rwlock_tryrdlock(pthread_rwlock_t *rw)
5 {
6 int result;
7 if (rw->rwjnagic != RW_MAGIC)
8 return(EINVAL);
9 if ((result = pthread_mutex_lock(&rw->rw_mutex)) != 0)
10 return(result);
11 if (rw->rw_refcount < 0 || rw->rw_nwaitwriters > 0)
12 result = EBUSY; /* блокировка установлена пишущим потоком или есть пишущие потоки, ожидающие освобождения ресурса */
13 else
14 rw->rw_refcount++; /* увеличение количества блокировок на чтение */
15 pthread_mutex_unlock(&rw->rw_mutex);
16 return(result);
17 }
11-14 Если блокировка в данный момент установлена на запись или есть процессы, ожидающие возможности установить ее на запись, возвращается ошибка с кодом EBUSY. В противном случае мы устанавливаем блокировку, увеличивая значение счетчика rw_refcount.
Функция pthread_rwlock_wrlock
Текст функции pthread_rwlock_wrlock приведен в листинге 8.6.
11-17 Если ресурс заблокирован на считывание или запись (значение rw_refcount отлично от 0), мы приостанавливаем выполнение потока. Для этого мы увеличиваем rw_nwaitwriters и вызываем pthread_cond_wait с условной переменной rw_condwriters. Для этой переменной посылается сигнал при снятии блокировки чтения-записи, если имеются ожидающие разрешения на запись процессы.
18-19 После получения блокировки на запись мы устанавливаем значение rw_refcount в –1.
Листинг 8.6. Функция pthread_rwlock_wrlock: получение блокировки на запись//my_rwlock/pthread_rwlock_wrlock.c
1 #include "unpipc.h"
2 #include "pthread_rwlock.h"
3 int
4 pthread_rwlock_wrlock(pthread_rwlock_t *rw)
5 {
6 int result;
7 if (rw->rw_magic != RW_MAGIC)
8 return(EINVAL);
9 if ((result = pthread_mutex_lock(&rw->rw_mutex)) != 0)
10 return(result);
11 while (rw->rw_refcount != 0) {
12 rw->rw_nwaitwriters++;
13 result = pthread_cond_wait(&rw->rw_condwriters, &rw->rw_mutex);
14 rw->rw_nwaitwriters--;
15 if (result != 0)
16 break;
17 }
18 if (result == 0)
19 rw->rw_refcount = –1;
20 pthread_mutex_unlock(&rw->rw_mutex);
21 return(result);
22 }
Функция pthread_rwlock_trywrlock
Неблокируемая функция pthread_rwlock_trywrlock показана в листинге 8.7.
11-14 Если значение счетчика rw_refcount отлично от нуля, блокировка в данный момент уже установлена считывающим или записывающим процессом (это безразлично) и мы возвращаем ошибку с кодом EBUSY. В противном случае мы устанавливаем блокировку на запись, присвоив переменной rw_refcount значение –1.
Листинг 8.7. Функция pthread_rwlock_trywrlock: попытка получения блокировки на запись//my_rwlock/pthread_rwlock_trywrlock.c
1 #include "unpipc.h"
2 #include "pthread_rwlock.h"
3 int
4 pthread_rwlock_trywrlock(pthread_rwlock_t *rw)
5 {
6 int result;
7 if (rw->rw_magic != RW_MAGIC)
8 return(EINVAL);
9 if ((result = pthread_mutex_lock(&rw->rw_mutex)) != 0)
10 return(result);
11 if (rw->rw_refcount != 0)
12 result = EBUSY; /* заблокирован пишущим потоком или ожидающим возможности записи */
13 else
14 rw->rw_refcount = –1; /* доступна */
15 pthread_mutex_unlock(&rw->rw_mutex);
16 return(result);
17 }
Функция pthread_rwlock_unlock
Последняя функция, pthread_rwlock_unlock, приведена в листинге 8.8.
Листинг 8.8. Функция pthread_rwlock_unlock: разблокирование ресурса//my_rwlock/pthread_rwlock_unlock.c
1 #include "unpipc.h"
2 #include "pthread_rwlock.h"
3 int
4 pthread_rwlock_unlock(pthread_rwlock_t *rw)
5 {
6 int result;
7 if (rw->rw_magic != RW_MAGIC)
8 return(EINVAL);
9 if ((result = pthread_mutex_lock(&rw->rw_mutex)) != 0)
10 return(result);
11 if (rw->rw_refcount > 0)
12 rw->rw_refcount--; /* снятие блокировки на чтение */
13 else if (rw->rw_refcount == –1)
14 rw->rw_refcount = 0; /* снятие блокировки на запись */
15 else
16 err_dump("rw_refcount = %d", rw->rw_refcount);
17 /* преимущество отдается ожидающим возможности записи потокам */
18 if (rw->rw_nwaitwriters > 0) {
19 if (rw->rw_refcount == 0)
20 result = pthread_cond_signal(&rw->rw_condwriters);
21 } else if (rw->rw_nwaitreaders > 0)
22 result = pthread_cond_broadcast(&rw->rw_condreaders);
23 pthread_mutex_unlock(&rw->rw_mutex);
24 return(result);
25 }
11-16 Если rw_refcount больше 0, считывающий поток снимает блокировку на чтение. Если rw_refcount равно –1, записывающий поток снимает блокировку на запись.
17-22 Если имеются ожидающие разрешения на запись потоки, по условной переменной rw_condwriters передается сигнал (если блокировка свободна, то есть значение счетчика rw_refcount равно 0). Мы знаем, что только один поток может осуществлять запись, поэтому используем функцию pthread_cond_signal. Если нет потоков, ожидающих возможности записи, но есть потоки, ожидающие возможности чтения, мы вызываем pthread_cond_broadcast для переменной rw_condreaders, поскольку возможно одновременное считывание несколькими потоками. Обратите внимание, что мы перестаем устанавливать блокировку для считывающих потоков, если появляются потоки, ожидающие возможности записи. В противном случае постоянно появляющиеся потоки с запросами на чтение могли бы заставить поток, ожидающий возможности записи, ждать целую вечность. По этой причине мы используем два отдельных оператора if и не можем написать просто:
/* предпочтение отдается записывающим процессам */
if (rw->rw_nwaitreaders > 0 && rw->rw_refcount == 0)
result = pthread_cond_signal(&rw->rw_condwriters);
else if (rw->rw_nwaitreaders > 0)
result = pthread_cond_broadcast(&rw->rw_condreaders);
Мы могли бы исключить и проверку rw->rw_refcount, но это может привести к вызовам pthread_cond_signal даже при наличии блокировок на чтение, что приведет к потере эффективности.
8.5. Отмена выполнения потоков
Обсуждая листинг 8.4, мы обратили внимание на наличие проблемы, возникающей при отмене выполнения потока, заблокированного вызовом pthread_cond_wait. Выполнение потока может быть отменено в том случае, если какой-нибудь другой поток вызовет функцию pthread_cancel, единственным аргументом которой является идентификатор потока, выполнение которого должно быть отменено:
#include <pthread.h>
int pthread_cancel(pthread_t tid);
/* Возвращает 0 в случае успешного завершения, положительное значение Еххх –в случае ошибки */
Отмена выполнения может быть использована в том случае, если несколько потоков начинают работу над какой-то задачей (например, поиск записи в базе данных) и один из них завершает работу раньше всех остальных. Тогда он может отменить их выполнение. Другим примером является обнаружение ошибки одним из одновременно выполняющих задачу потоков, который затем может отменить выполнение и всех остальных.
Для обработки отмены выполнения поток может установить (push) или снять (pop) обработчик-очиститель (cleanup handler):
#include <pthread.h>
void pthread_cleanup_push(void (*function) (void *) void *arg);
void pthread_cleanup_pop(int execute);
Эти обработчики представляют собой обычные функции, которые вызываются:
■ в случае отмены выполнения потока (другим потоком, вызвавшим pthread_ cancel);
■ в случае добровольного завершения работы (вызовом pthread_exit или выходом из начальной функции потока).
Обработчики-очистители выполняют всю необходимую работу по восстановлению значений переменных, такую как разблокирование взаимных исключений и семафоров, которые могли быть заблокированы данным потоком.
Аргумент function представляет собой адрес вызываемой функции, а arg — ее единственный аргумент. Функция pthread_cleanup_pop всегда удаляет обработчик из верхушки стека и вызывает эту функцию, если значение execute отлично от 0.
ПРИМЕЧАНИЕ
Мы снова встретимся с проблемой отмены выполнения потоков в связи с листингом 15.26, где может произойти отмена выполнения сервера с дверьми при завершении работы клиента в процессе обработки вызванной им процедуры.
Пример
Легче всего продемонстрировать проблему нашей реализации из предыдущего раздела с помощью примера. На рис. 8.1 изображена временная диаграмма выполнения нашей программы, а текст самой программы приведен в листинге 8.9.
Рис. 8.1. Временная диаграмма выполнения программы из листинга 8.9