#include
#include
#include
/* Ожидание семафора. Операция блокируется до тех пор, пока
значение семафора не станет положительным, после чего
значение уменьшается на единицу. */
int binary_semaphore_wait(int semid) {
struct sembuf operations[1];
/* Оперируем одним-единственным семафором. */
operations[0].sem_num = 0;
/* Уменьшаем его значение на единицу. */
operations[0].sem_op = -1;
/* Разрешаем отмену операции. */
operations[0].sem_flg = SEM_UNDO;
return semop(semid, operations, 1);
}
/* Установка семафора: его значение увеличивается на единицу.
Эта операция завершается немедленно. */
int binary_semaphore_post(int semid) {
struct sembuf operations[1];
/* оперируем одним-единственным семафором. */
operations[0].sem_num = 0;
/* Увеличиваем его значение на единицу. */
operations[0].sem_op = 1;
/* Разрешаем отмену операции. */
operations[0].sem_flg = SEM_UNDO;
return semop(semid, operations, 1);
}
Флаг SEM_UNDO
позволяет решить проблему, возникающую при завершении процесса, которого есть ресурсы, связанные с семафором. Как бы ни завершился процесс — принудительно или естественным образом, — значение семафора автоматически корректируется. "отменяя" эффект операции, выполненной над семафором. Например, если процесс уменьшил значение семафора, а затем был уничтожен командой kill
, значение семафора будет снова увеличено.
5.2.4. Отладка семафоров
С помощью команды ipcs -s
можно получить информацию о существующих группах семафоров. Команда ipcrm sem
позволяет удалить заданную группу, например:
% ipcrm sem 5790517
5.3. Отображение файлов в памяти
Благодаря механизму отображаемой памяти процессы получают возможность общаться друг с другом посредством совместно используемого файла. Схематически это можно представить как совместный доступ к именованному сегменту памяти, хотя технически оба механизма реализованы по-разному.
При отображении файла в памяти формируется связь между файлом и памятью процесса. ОС Linux разбивает файл на страничные блоки и копирует их в страницы виртуальной памяти, чтобы они стали доступны в адресном пространстве процесса. Таким образом, процесс сможет обращаться к содержимому файла как к обычной памяти. При записи данных в соответствующую область памяти содержимое файла будет меняться. Это ускоряет доступ к файлам.
Отображаемую память можно представить как буфер, в который загружается все содержимое файла. Если данные, находящиеся в буфере, модифицируются, они записываются обратно в файл. Операции чтения и записи ОС Linux обрабатывает самостоятельно.
Файлы, отображаемые в памяти, можно использовать не только для организации взаимодействия процессов. О других применениях таких файлов пойдет речь в разделе 5.3.5. "Другие применения функции mmap()".
5.3.1. Отображение в памяти обычного файла
Для отображения обычного файла в памяти процесса предназначена функция mmap()
. Ее первым аргументом является адрес, который будет соответствовать началу отображаемого файла в адресном пространстве процесса. Если задать значение NULL
, ОС Linux выберет первый доступный адрес. Второй аргумент — это длина отображаемой области в байтах. Третий аргумент задает степень защиты диапазона отображаемых адресов. Он может содержать объединение битовых констант PROT_READ
, PROT_WRITE
и PROT_EXEC
, соответствующих разрешению на чтение, запись и выполнение соответственно. Четвертый аргумент содержит дополнительные флаги. Пятый аргумент — это дескриптор открытого файла. В последнем аргументе задается смещение от начала файла, с которого начинается отображаемая область. Можно перенести в память весь файл или только часть его, должным образом корректируя начальное смещение и длину отображаемой области.
Ниже перечислены дополнительные флаги, задаваемые в четвертом аргументе.
■ MAP_FIXED
. При наличии этого флага ОС Linux использует значение первого аргумента как точный адрес размещения отображаемого файла. Этот адрес должен соответствовать началу страницы.