- •Часть 4. Локальное взаимодействие процессов
- •Глава 16. Блокирование записей 89
- •12.2. Процессы, потоки и общий доступ к информации
- •12.3. Живучесть объектов ipc
- •12.4. Пространства имен
- •12.5. Действие команд fork, exec и exit на объекты ipc
- •12.6. Комментарии к примерам ipc
- •12.7. Выводы по главе 12
- •12.8. Упражнения по главе 12
- •Глава 13. Именованные и неименованные каналы
- •13.1. Введение
- •13.2. Приложение типа клиент-сервер
- •13.3. Программные каналы
- •13.4. Функции popen и pclose
- •13.5. Именованные каналы (fifo)
- •13.6. Некоторые свойства именованных и неименованных каналов
- •13.7. Один сервер, несколько клиентов
- •13.8. Последовательные и параллельные серверы
- •13.9. Ограничения программных каналов и fifo
- •13.10. Выводы по главе 13
- •13.11. Упражнения по главе 13
- •Глава 14. Программные потоки
- •14.1. Введение
- •14.2. Концепция потоков
- •14.3. Идентификация потоков
- •14.4. Создание потока
- •14.5. Завершение потока
- •Функции управления процессами и потоками
- •14.6. Установка атрибутов потока
- •14.7. Реентерабельность
- •Альтернативные версии функций, безопасные в многопоточной среде
- •14.8. Локальные данные потоков
- •14.9. Принудительное завершение потоков
- •Некоторые точки выхода, определенные стандартом Posix.1
- •14.10. Потоки и сигналы
- •14.11. Выводы по главе 14
- •14.12. Упражнения по главе 14 Глава 15. Средства синхронизации потоков
- •15.1. Введение
- •15.2. Взаимные исключения: установка и снятие блокировки
- •15.2.1. Схема производитель-потребитель
- •15.2.2. Блокирование и опрос
- •15.2.3. Предотвращение тупиковых ситуаций
- •15.3. Условные переменные
- •15.3.1. Ожидание и сигнализация
- •15.3.2. Исключение состояния гонок
- •15.4. Блокировки чтения-записи
- •15.5. Атрибуты средств синхронизации потоков
- •15.5.1. Атрибуты взаимных исключений
- •Поведение взаимных исключений различных типов
- •15.5.2. Атрибуты условных переменных
- •15.5.3. Атрибуты блокировок чтения-записи
- •15.6. Выводы по главе 15
- •15.7. Упражнения по главе 15
- •Глава 16. Блокирование записей
- •16.1. Введение
- •16.2. Блокирование записей и файлов
- •16.3. Блокирование записей с помощью fcntl по стандарту Posix
- •16.4. Рекомендательная блокировка
- •16.5. Обязательная блокировка
- •16.6. Приоритет чтения и записи Выводы по главе 16
- •Упражнения по главе 16 Глава 17. System V ipc
- •17.1. Введение
- •17.2. Ключи типа key_t и функция ftok
- •17.3. Структура ipc_perm
- •17.4. Создание и открытие каналов ipc
- •17.5. Разрешения ipc
- •17.6. Программы ipcs и ipcrm
- •17.7. Ограничения ядра
- •17.8. Выводы по главе 17
- •17.9. Упражнения по главе 17
- •Глава 18. Очереди сообщений System V
- •18.1. Введение
- •18.2. Функция msgget
- •18.3. Функция msgsnd
- •18.4. Функция msgrcv
- •18.5. Функция msgctl
- •18.6. Пример программы клиент-сервер
- •18.7. Мультиплексирование сообщений
- •18.7.1. Пример: одна очередь на приложение
- •18.7.2. Пример: одна очередь для каждого клиента
- •18.8. Ограничения, накладываемые на очереди сообщений
- •18.9. Выводы по главе 18
- •18.10. Упражнения по главе 18
- •Глава 19. Семафоры System V
- •19.1. Введение
- •19.2. Функция semget
- •19.3. Функция semop
- •19.4. Функция semctl
- •19. . Ограничения семафоров System V
- •19. . Выводы по главе 19
- •19. . Упражнения по главе 19 Глава 20. Введение в разделяемую память
- •20.1. Введение
- •20.2. Функции mmap, munmap и msync
- •20.3. Увеличение счетчика в отображаемом в память файле
- •20.4. Неименованное отображение в память
- •20.5. Обращение к объектам, отображенным в память
- •20.6. Выводы по главе 20
- •20.7. Упражнения по главе 20
- •Глава 21. Разделяемая память System V
- •21.1. Введение
- •21.2. Функция shmget
- •21.3. Функция shmat
- •21.4. Функция shmdt
- •21.5. Функция shmctl
- •21.6. Ограничения, накладываемые на разделяемую память
- •21.7. Выводы по главе 21
- •21.8. Упражнения по главе 21
15.5. Атрибуты средств синхронизации потоков
В наших примерах в этой главе мы хранили взаимные исключения, условные переменные и блокировки чтения-записи как глобальные данные всего процесса, поскольку они использовались для синхронизации потоков внутри него. Инициализировали мы их с помощью трех констант: PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZERи PTHREAD_RWLOCK_INITIALIZERсоответственно. Инициализируемые таким образом средства синхронизации потоков приобретали значения атрибутов по умолчанию, но мы можем инициализировать их и с другими значениями атрибутов.
15.5.1. Атрибуты взаимных исключений
Атрибуты взаимного исключения имеют тип pthread_mutexattr_t. Они инициализируются и разрушаются с помощью двух указанных ниже функций.
#include<pthread.h>
int pthread_mutexattr_init (pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy (pthread_mutexattr_t *attr);
/* обе функции возвращают 0 в случае успешного завершения, код ошибки – в случае неудачи */
Функция pthread_mutexattr_initинициализирует структуруpthread_mutexattr_t, содержащую атрибуты взаимного исключения, значениями по умолчанию. Здесь представляют интерес два атрибута:process_sharedиtype. Согласно стандарту Posix.1 атрибутprocess_sharedявляется необязательным. Если он поддерживается в конкретной операционной системе, то будет определен и символ_POSIX_THREAD_PROCESS_SHARED.
Внутри процесса множество потоков могут иметь доступ к одному и тому же объекту синхронизации. Такое поведение определено по умолчанию. В этом случае атрибут взаимного исключения process_sharedимеет значениеPTHREAD_PROCESS_PRIVATE.
Как мы увидим в главе 20, существуют механизмы, позволяющие независимым друг от друга процессам (родственникам?) отображать одну и ту же область памяти в свои собственные адресные пространства. Доступ к данным, совместно используемым несколькими процессами, обычно требует синхронизации, так же как и доступ к совместно используемым данным из нескольких потоков. Если атрибутуprocess_sharedприсвоено значениеPTHREAD_PROCESS_SHARED, то взаимное исключение может быть размещено в области памяти, разделяемой между несколькими процессами, и использоваться для синхронизации действий этих процессов.
Получить значение атрибута process_sharedструктурыpthread_mutexattr_tможно с помощью функцииpthread_mutexattr_getpshared. Чтобы установить значение этого атрибута, следует использовать функциюpthread_mutexattr_setpshared.
#include<pthread.h>
int pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr, int *pshared);
int pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared);
/* обе функции возвращают 0 в случае успешного завершения, код ошибки – в случае неудачи */
Атрибут typeпозволяет указать тип взаимного исключения. Стандарт Posix.1 определяет четыре типа. ТипPTHREAD_MUTEX_NORMAL – это стандартное взаимное исключение, которое не проверяет наличие ошибок или тупиковых ситуаций. Взаимные исключения типаPTHREAD_MUTEX_ERRORCHECKпроизводят проверку наличия ошибок.
Взаимные исключения типа PTHREAD_MUTEX_RECURSIVEпозволяют одному и тому же потоку многократно запирать взаимное исключение, не отпирая его. Рекурсивные взаимные исключения содержат счетчик, который хранит количество запираний взаимного исключения. Взаимное исключение будет свободно только тогда, когда количество отпираний совпадет с количеством запираний. Так, если имеется рекурсивное взаимное исключение, которое было заперто дважды, а отперто всего лишь один раз, то оно все равно останется занятым до тех пор, пока не будет отперто еще один раз.
И, наконец, взаимные исключения типа PTHREAD_MUTEX_DEFAULTмогут использоваться для назначения модели поведения по умолчанию для взаимных исключений. Реализации могут самостоятельно определять, какой из трех описанных выше типов взаимных исключений выбрать как тип по умолчанию. Так, например, в ОС Linux в качестве типа взаимного исключения по умолчанию выбран типPTHREAD_MUTEX_NORMAL.
Чтобы получить значение атрибута type, можно использовать функциюpthread_mutexattr_gettype. Чтобы установить значение этого атрибута, следует использовать функциюpthread_mutexattr_settype.
#include<pthread.h>
int pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type);
int pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type);
/* обе функции возвращают 0 в случае успешного завершения, код ошибки – в случае неудачи */
Таблица 15.1
