- •Часть 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
19.3. Функция semop
После инициализации семафора вызовом semgetс одним или несколькими семафорами набора можно выполнять некоторые действия с помощью функцииsemop:
#include <sys/sem.h>
int semop (int semid, struct sembuf *opsptr, size_t nops);
/* возвращает 0 в случае успешного завершения, -1 – в случае ошибки */
Указатель opsptrуказывает на массив структур следующего вида:
struct sembuf
{
unsigned short sem_num; /* номер семафора: 0, 1, ..., sem_nsems-1 */
short sem_op; /* операция над семафором: <0, 0, >0 */
short sem_flg; /* флаги операции: 0, IPC_NOWAIT, SEM_UNDO */
};
Количество элементов в массиве структур sembuf, на который указываетopsptr, задается аргументомnops. Каждый элемент этого массива определяет операцию с одним конкретным семафором набора. Номер семафора указывается в полеsem_numи принимает значение 0 для первого семафора, 1 – для второго и т. д., доsem_nsems-1, гдеsem_nsemsсоответствует количеству семафоров в наборе (второй аргумент в вызовеsemgetпри создании семафора).
Весь массив операций, передаваемый функции semop, выполняется ядром как одна операция; атомарность при этом гарантируется. Ядро выполняет все указанные операции или ни одну из них.
Каждая операция задается значением sem_op, которое может быть отрицательным, нулевым или положительным. Сделаем несколько утверждений, которыми мы будем пользоваться при дальнейшем обсуждении:
semval– текущее значение семафора (рис. 18.2);
semncnt– количество потоков, ожидающих, пока значение семафора не увеличится (рис. 18.2);
semzcnt– количество потоков, ожидающих, пока значение семафора не станет нулевым (рис. 18.2);
semadj– корректировочное значение данного семафора для вызвавшего процесса. Это значение изменяется, только если при вызове функцииsemopв полеsem_flgструктурыsembufбыл указан флагSEM_UNDO. Эта переменная создается в ядре для каждого процесса в отдельности, который указал флагSEM_UNDO;
когда выполнение потока приостанавливается до завершения операции с семафором (мы увидим, что поток может ожидать либо обнуления семафора, либо получения семафором положительного значения), поток может перехватить сигнал. По возвращении из обработчика сигнала функция semopвозвращает ошибкуEINTR. Другими словами, функцияsemopпредставляет собой медленный системный вызов (раздел 10.5), который может быть прерван перехватываемыми сигналами;
когда выполнение потока приостанавливается до завершения операции с семафором и этот семафор удаляется из системы другим потоком или процессом, функция semopвозвращает ошибкуEIDRM.
Опишем теперь работу функции semopв зависимости от трех возможных значений, которые может принимать полеsem_opструктурыsembuf: положительного, нулевого и отрицательного.
Если значение sem_opположительно, оно добавляется кsemval. Такое действие соответствует освобождению ресурсов, доступом к которым управляет семафор. Если указан флагSEM_UNDO, значениеsem_opвычитается из значенияsemadjданного семафора.
Если значение sem_opравно нулю, вызвавший поток блокируется до тех пор, пока текущее значение семафора (semval) не станет нулевым. Еслиsemvalуже равно нулю, происходит немедленный возврат из функции.
Если значение semvalне равно нулю, то ядро увеличивает значение поляsemzcntданного семафора и вызвавший поток блокируется до тех пор, пока значениеsemvalне станет нулевым (после чего значениеsemzcntбудет уменьшено на единицу). Как отмечалось ранее, поток будет приостановлен, только если не указан флагIPC_NOWAIT. Если семафор будет удален в процессе ожидания или будет перехвачен сигнал, произойдет преждевременный возврат из функции и будет возвращен соответствующий код ошибки.
Если значение sem_opотрицательно, вызвавший поток блокируется до тех пор, пока текущее значение семафора не станет большим или равным модулюsem_op. Это действие соответствует запросу ресурсов. Если значениеsemvalбольше или равно модулюsem_op, модульsem_opвычитается изsemval. Если указан флагSEM_UNDO, модульsem_opдобавляется к значениюsemadjданного семафора.
Если значение semvalменьше модуляsem_op, значение поляsemncntданного семафора увеличивается на единицу, а вызвавший поток блокируется до тех пор, пока значениеsemvalне станет большим или равным модулюsem_op. Когда это произойдет, поток будет разблокирован, значениеsemvalбудет уменьшено на модульsem_opи из значенияsemncntбудет вычтена единица. Если указан флагSEM_UNDO, модульsem_opдобавляется к значениюsemadjданного семафора. Как отмечалось ранее, поток не будет приостановлен, если указан флагIPC_NOWAIT. Ожидание завершается преждевременно, если будет перехвачен сигнал или семафор будет удален другим потоком.
