Чтение онлайн

на главную - закладки

Жанры

Шрифт:

static struct sembuf sop_lock[2] = {

 0, 0, 0, /* ожидать обнуления семафора */

 0, 1, 0 /* затем увеличить значение семафора на 1 */

};

static struct sembuf sop_unlock[1] = {

 0,-1, 0 /* обнулить значение семафора */

};

Итак, для запирания ресурса процесс производит вызов:

semop(semid, &sop_lock[0], 2);

обеспечивающий атомарное выполнение двух операций: [43]

43

Ядро

обеспечивает атомарное выполнение не всего набора операций в целом, а лишь критических участков. Так, например, в процессе ожидания освобождения ресурса (ожидание нулевого значения семафора) выполнение процесса будет (и должно быть) прервано процессом, который освободит ресурс (т.е. установит значение семафора равным 1). Ожидание семафора соответствует состоянию "сна" процесса, допускающим выполнение других процессов в системе. В противном случае, процесс, ожидающий ресурс, остался бы заблокированным навсегда.

1. Ожидание доступности ресурса. В случае, если ресурс уже занят (значение семафора равно 1), выполнение процесса будет приостановлено до освобождения ресурса (значение семафора равно 0).

2. Запирание ресурса. Значение семафора устанавливается равным 1. Для освобождения ресурса процесс должен произвести вызов:

semop(semid, &sop_unlock[0], 1);

который уменьшит текущее значение семафора (равное 1) на 1, и оно станет равным 0, что соответствует освобождению ресурса. Если какой-либо из процессов ожидает ресурса (т. е. произвел вызов операции

sop_lock
), он будет "разбужен" системой, и сможет в свою очередь запереть ресурс и работать с ним.

Во втором примере изменим трактовку значений семафора: значению 1 семафора соответствует доступность некоторого ассоциированного с семафором ресурса, а нулевому значению — его недоступность. В этом случае содержание операций несколько изменится.

static struct sembuf sop_lock[2] = {

 0, -1, 0, /* ожидать разрешающего сигнала (1),

затем обнулить семафор */

};

static struct sembuf sop_unlock[1] = {

 0, 1, 0 /* увеличить значение семафора на 1 */

};

Процесс запирает ресурс вызовом:

semop(semid, &sop_lock[0], 1);

а освобождает:

semop(semid, &sop_unlock[0], 1);

Во втором случае операции получились проще (по крайней мере их код стал компактнее), однако этот подход имеет потенциальную опасность: при создании семафора, его значения устанавливаются равными 0, и во втором случае он сразу же запирает ресурс. Для преодоления данной ситуации процесс, первым создавший семафор, должен вызвать операцию

sop_unlock
, однако в этом случае процесс инициализации семафора перестанет быть атомарным и может быть прерван другим процессом, который, в свою очередь, изменит значение семафора. В итоге, значение семафора станет равным 2, что повредит нормальной работе с разделяемым ресурсом.

Можно предложить следующее решение данной проблемы:

/* Создаем семафор, если он уже существует 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 <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

int shmget(key_t key, int size, int shmflag);

Функция возвращает дескриптор разделяемой памяти в случае успеха, и -1 в случае неудачи. Аргумент

size
определяет размер создаваемой области памяти в байтах. Значения аргумента
shmflag
задают права доступа к объекту и специальные флаги
IPC_CREAT
и
IPC_EXCL
. Заметим, что вызов shmget(2) лишь создает или обеспечивает доступ к разделяемой памяти, но не позволяет работать с ней. Для работы с разделяемой памятью (чтение и запись) необходимо сначала присоединить (attach) область вызовом shmat(2):

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

char *shmat(int shmid, char *shmaddr, int shmflag);

Вызов shmat(2) возвращает адрес начала области в адресном пространстве процесса размером

size
, заданным предшествующем вызовом shmget(2). В этом адресном пространстве взаимодействующие процессы могут размещать требуемые структуры данных для обмена информацией. Правила получения этого адреса следующие:

Поделиться:
Популярные книги

Блуждающие огни 4

Панченко Андрей Алексеевич
4. Блуждающие огни
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Блуждающие огни 4

Я сделаю это сама

Кальк Салма
1. Магический XVIII век
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Я сделаю это сама

Флеш Рояль

Тоцка Тала
Детективы:
триллеры
7.11
рейтинг книги
Флеш Рояль

Боярышня Дуняша

Меллер Юлия Викторовна
1. Боярышня
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Боярышня Дуняша

Газлайтер. Том 8

Володин Григорий
8. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 8

Леди для короля. Оборотная сторона короны

Воронцова Александра
3. Королевская охота
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Леди для короля. Оборотная сторона короны

На границе империй. Том 10. Часть 1

INDIGO
Вселенная EVE Online
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 10. Часть 1

Черный Маг Императора 5

Герда Александр
5. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 5

Невест так много. Дилогия

Завойчинская Милена
Невест так много
Любовные романы:
любовно-фантастические романы
7.62
рейтинг книги
Невест так много. Дилогия

Идеальный мир для Социопата 3

Сапфир Олег
3. Социопат
Фантастика:
боевая фантастика
6.17
рейтинг книги
Идеальный мир для Социопата 3

Повелитель механического легиона. Том VIII

Лисицин Евгений
8. Повелитель механического легиона
Фантастика:
технофэнтези
аниме
фэнтези
5.00
рейтинг книги
Повелитель механического легиона. Том VIII

Наследник павшего дома. Том I

Вайс Александр
1. Расколотый мир
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Наследник павшего дома. Том I

Крещение огнем

Сапковский Анджей
5. Ведьмак
Фантастика:
фэнтези
9.40
рейтинг книги
Крещение огнем

Камень Книга двенадцатая

Минин Станислав
12. Камень
Фантастика:
боевая фантастика
городское фэнтези
аниме
фэнтези
5.00
рейтинг книги
Камень Книга двенадцатая