Андрей Робачевский - Операционная система UNIX
- Название:Операционная система UNIX
- Автор:
- Жанр:
- Издательство:BHV - Санкт-Петербург
- Год:1997
- Город:Санкт-Петербург
- ISBN:5-7791-0057-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Андрей Робачевский - Операционная система UNIX краткое содержание
Книга посвящена семейству операционных систем UNIX и содержит информацию о принципах организации, идеологии и архитектуре, объединяющих различные версии этой операционной системы.
В книге рассматриваются: архитектура ядра UNIX (подсистемы ввода/вывода, управления памятью и процессами, а также файловая подсистема), программный интерфейс UNIX (системные вызовы и основные библиотечные функции), пользовательская среда (командный интерпретатор shell, основные команды и утилиты) и сетевая поддержка в UNIX (протоколов семейства TCP/IP, архитектура сетевой подсистемы, программные интерфейсы сокетов и TLI).
Для широкого круга пользователей
Операционная система UNIX - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Можно предложить следующее решение данной проблемы:
/* Создаем семафор, если он уже существует semget
возвращает ошибку, поскольку указан флаг IPC_EXCL */
if ((semid = semget(key, nsems, perms | IPC_CREAT | IPC_EXCL)) < 0) {
if (errno = EEXIST) {
/* Действительно, ошибка вызвана существованием объекта */
if ((semid = semget(key, nsems, perms)) < 0)
return(-1); /* Возможно, не хватает системных ресурсов */
} else
return(-1); /* Возможно, не хватает системных ресурсов * /
}
/* Если семафор создан нами, проинициализируем его */
else
semop(semid, &sop_unlock[0], 1);
Разделяемая память
Интенсивный обмен данными между процессами с использованием рассмотренных механизмов межпроцессного взаимодействия (каналы, FIFO, очереди сообщений) может вызвать падение производительности системы. Это, в первую очередь, связано с тем, что данные, передаваемые с помощью этих объектов, копируются из буфера передающего процесса в буфер ядра и затем в буфер принимающего процесса. Механизм разделяемой памяти позволяет избавиться от накладных расходов передачи данных через ядро, предоставляя двум или более процессам возможность непосредственного получения доступа к одной области памяти для обмена данными.
Безусловно, процессы должны предварительно "договориться" о правилах использования разделяемой памяти. Например, пока один из процессов производит запись данных в разделяемую память, другие процессы должны воздержаться от работы с ней. К счастью, задача кооперативного использования разделяемой памяти, заключающаяся в синхронизации выполнения процессов, легко решается с помощью семафоров.
Примерный сценарий работы с разделяемой памятью выглядит следующим образом:
1. Сервер получает доступ к разделяемой памяти, используя семафор.
2. Сервер производит запись данных в разделяемую память.
3. После завершения записи сервер освобождает разделяемую память с помощью семафора.
4. Клиент получает доступ к разделяемой памяти, запирая ресурс с помощью семафора.
5. Клиент производит чтение данных из разделяемой памяти и освобождает ее, используя семафор.
Для каждой области разделяемой памяти, ядро поддерживает структуру данных shmid_ds
, основными полями которой являются:
struct ipc_perm shm_perm |
Права доступа, владельца и создателя области (см. описание ipc_perm выше) |
int shm_segsz |
Размер выделяемой памяти |
ushort shm_nattch |
Число процессов, использующих разделяемую память |
time_t shm_atime |
Время последнего присоединения к разделяемой памяти |
time_t shm_dtime |
Время последнего отключения от разделяемой памяти |
time_t shm_ctime |
Время последнего изменения |
Для создания или для доступа к уже существующей разделяемой памяти используется системный вызов shmget(2) :
#include
#include
#include
int shmget(key_t key, int size, int shmflag);
Функция возвращает дескриптор разделяемой памяти в случае успеха, и -1 в случае неудачи. Аргумент size
определяет размер создаваемой области памяти в байтах. Значения аргумента shmflag
задают права доступа к объекту и специальные флаги IPC_CREAT
и IPC_EXCL
. Заметим, что вызов shmget(2) лишь создает или обеспечивает доступ к разделяемой памяти, но не позволяет работать с ней. Для работы с разделяемой памятью (чтение и запись) необходимо сначала присоединить (attach) область вызовом shmat(2) :
#include
#include
#include
char *shmat(int shmid, char *shmaddr, int shmflag);
Вызов shmat(2) возвращает адрес начала области в адресном пространстве процесса размером size
, заданным предшествующем вызовом shmget(2) . В этом адресном пространстве взаимодействующие процессы могут размещать требуемые структуры данных для обмена информацией. Правила получения этого адреса следующие:
1. Если аргумент shmaddr
нулевой, то система самостоятельно выбирает адрес.
2. Если аргумент shmaddr
отличен от нуля, значение возвращаемого адреса зависит от наличия флажка SHM_RND
в аргументе shmflag
:
• Если флажок SHM_RND
не установлен, система присоединяет разделяемую память к указанному shmaddr
адресу.
• Если флажок SHM_RND
установлен, система присоединяет разделяемую память к адресу, полученному округлением в меньшую сторону shmaddr
до некоторой определенной величины SHMLBA
.
По умолчанию разделяемая память присоединяется с правами на чтение и запись. Эти права можно изменить, указав флажок SHM_RDONLY
в аргументе shmflag
.
Таким образом, несколько процессов могут отображать область разделяемой памяти в различные участки собственного виртуального адресного пространства, как это показано на рис. 3.20.

Рис. 3.20. Совместное использование разделяемой памяти
Окончив работу с разделяемой памятью, процесс отключает (detach) область вызовом shmdt(2) :
#include
#include
#include
int shmdt(char *shmaddr);
При работе с разделяемой памятью необходимо синхронизировать выполнение взаимодействующих процессов: когда один из процессов записывает данные в разделяемую память, остальные процессы ожидают завершения операции. Обычно синхронизация обеспечивается с помощью семафоров, назначение и число которых определяется конкретным использованием разделяемой памяти.
Можно привести примерную схему обмена данными между двумя процессами (клиентом и сервером) с использованием разделяемой памяти. Для синхронизации процессов использована группа из двух семафоров. Первый семафор служит для блокирования доступа к разделяемой памяти, его разрешающий сигнал — 0, а 1 является запрещающим сигналом. Второй семафор служит для сигнализации серверу о том, что клиент начал работу. Необходимость применения второго семафора обусловлена следующими обстоятельствами: начальное состояние семафора, синхронизирующего работу с памятью, является открытым (0), и вызов сервером операции заблокирует обращение к памяти для клиента. Таким образом, сервер должен вызвать операцию mem_lock
только после того, как разделяемую память заблокирует клиент. Назначение второго семафора заключается в уведомлении сервера, что клиент начал работу, заблокировал разделяемую память и начал записывать данные в эту область. Теперь, при вызове сервером операции mem_lock его выполнение будет приостановлено до освобождения памяти клиентом, который делает это после окончания записи строки "Здравствуй, Мир!".
#define MAXBUFF 80
Интервал:
Закладка: