Управление разделяемой памятью.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
Данный вызов используется для получения или изменения процессом управляющих параметров, связанных с областью разделяемой памяти, наложения и снятия блокировки на нее и ее уничтожения. Аргументы вызова — дескриптор области памяти, команда, которую необходимо выполнить, и структура, описывающая управляющие параметры области памяти. Тип shmid_ds описан в заголовочном файле <sys/shm.h>, и представляет собой структуру, в полях которой хранятся права доступа к области памяти, ее размер, число процессов, подсоединенных к ней в данный момент, и статистика обращений к области памяти.
Возможные значения аргумента cmd:
IPC_STAT – скопировать структуру, описывающую управляющие параметры области памяти по адресу, указанному в параметре buf
IPC_SET – заменить структуру, описывающую управляющие параметры области памяти, на структуру, находящуюся по адресу, указанному в параметре buf. Выполнить эту операцию может процесс, у которого эффективный идентификатор пользователя совпадает с владельцем или создателем очереди, либо процесс с правами привилегированного пользователя, при этом процесс может изменить только владельца области памяти и права доступа к ней.
IPC_RMID – удалить очередь. Как уже говорилось, удалить очередь может только процесс, у которого эффективный идентификатор пользователя совпадает с владельцем или создателем очереди, либо процесс с правами привилегированного пользователя.
SHM_LOCK,SHM_UNLOCK – блокировать или разблокировать область памяти. Выполнить эту операцию может только процесс с правами привилегированного пользователя.
XIII. Общая схема работы с общей памятью в рамках одного процесса.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int putm(char *);
int waitprocess(void);
int main(int argc, char **argv)
{
key_t key;
int shmid;
char *shmaddr;
key = ftok(“/tmp/ter”,’S’);
shmid = shmget(key, 100, 0666|IPC_CREAT);
shmaddr = shmat(shmid, NULL, 0); /* подключение к памяти */
putm(shmaddr); /* работа с ресурсом */
waitprocess();
shmctl(shmid,IPC_RMID,NULL); /* уничтожение ресурса */
return 0;
}
В данном примере считается, что putm() и waitprocess() – некие пользовательские функции, определенные в другом месте
БИЛЕТ 42
Семафоры.
Семафоры представляют собой одну из форм IPC и, как правило, используются для синхронизации доступа нескольких процессов к разделяемым ресурсам, так как сами по себе другие средства IPC не предоставляют механизма синхронизации.
Как уже говорилось, семафор представляет собой особый вид числовой переменной, над которой определены две неделимые операции: уменьшение ее значения с возможным блокированием процесса и увеличение значения с возможным разблокированием одного из ранее заблокированных процессов. Объект System V IPC представляет собой набор семафоров. Как правило, использование семафоров в качестве средства синхронизации доступа к другим разделяемым объектам предполагает следующую схему:
- с каждым разделяемым ресурсом связывается один семафор из набора;
- положительное значение семафора означает возможность доступа к ресурсу (ресурс свободен), неположительное – отказ в доступе (ресурс занят);
- перед тем как обратиться к ресурсу, процесс уменьшает значение соответствующего ему семафора, при этом, если значение семафора после уменьшения должно оказаться отрицательным, то процесс будет заблокирован до тех пор, пока семафор не примет такое значение, чтобы при уменьшении его значение оставалось неотрицательным;
- закончив работу с ресурсом, процесс увеличивает значение семафора (при этом разблокируется один из ранее заблокированных процессов, ожидающих увеличения значения семафора, если таковые имеются);
- в случае реализации взаимного исключения используется двоичный семафор, т.е. такой, что он может принимать только значения 0 и 1: такой семафор всегда разрешает доступ к ресурсу не более чем одному процессу одновременно
Рассмотрим набор вызовов для оперирования с семафорами в UNIX System V.
Доступ к семафору
Для получения доступа к массиву семафоров (или его создания) используется системный вызов:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflag);
Первый параметр функции semget() – ключ для доступа к разделяемому ресурсу, второй - количество семафоров в создаваемом наборе (длина массива семафоров) и третий параметр – флаги, управляющие поведением вызова. Подробнее процесс создания разделяемого ресурса описан выше. Отметим семантику прав доступа к такому типу разделяемых ресурсов, как семафоры: процесс, имеющий право доступа к массиву семафоров по чтению, может проверять значение семафоров; процесс, имеющий право доступа по записи, может как проверять, так и изменять значения семафоров.
В случае, если среди флагов указан IPC_CREAT, аргумент nsems должен представлять собой положительное число, если же этот флаг не указан, значение nsems игнорируется. Отметим, что в заголовочном файле <sys/sem.h> определена константа SEMMSL, задающая максимально возможное число семафоров в наборе. Если значение аргумента nsemsбольше этого значения, вызов semget() завершится неудачно.
В случае успеха вызов semget() возвращает положительный дескриптор созданного разделяемого ресурса, в случае неудачи -1.
Операции над семафором
Используя полученный дескриптор, можно производить изменять значения одного или нескольких семафоров в наборе, а также проверять их значения на равенство нулю, для чего используется системный вызов semop():
#include <sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
int semop(int semid, struct sembuf *semop, size_t nops)
Этому вызову передаются следующие аргументы:
semid – дескриптор массива семафоров;
semop – массив из объектов типа struct sembuf, каждый из которых задает одну операцию над семафором;
nops – длина массива semop. Количество семафоров, над которыми процесс может одновременно производить операцию в одном вызове semop(), ограничено константой SEMOPM, описанной в файле <sys/sem.h>. Если процесс попытается вызвать semop() с параметром nops, большим этого значения, этот вызов вернет неуспех.
Структура имеет sembuf вид:
struct sembuf {
short sem_num; /* номер семафора в векторе */
short sem_op; /* производимая операция */
short sem_flg; /* флаги операции */
}
Поле операции в структуре интерпретируется следующим образом:
Пусть значение семафора с номером sem_num равно sem_val.
1. если значение операции не равно нулю:
§ оценивается значение суммы sem_val + sem_op.
§ если эта сумма больше либо равна нулю, то значение данного семафора устанавливается равным этой сумме: sem_val = sem_val + sem_op
§ если же эта сумма меньше нуля, то действие процесса будет приостановлено до тех пор, пока значение суммы sem_val + sem_op не станет больше либо равно нулю, после чего значение семафора устанавливается равным этой сумме: sem_val = sem_val + sem_op
2. Если код операции sem_op равен нулю:
§ Если при этом значение семафора (sem_val) равно нулю, происходит немедленный возврат из вызова
§ Иначе происходит блокирование процесса до тех пор, пока значение семафора не обнулится, после чего происходит возврат из вызова
Таким образом, ненулевое значение поля sem_op обозначает необходимость прибавить к текущему значению семафора значение sem_op, а нулевое – дождаться обнуления семафора.
Поле sem_flg в структуре sembuf содержит комбинацию флагов, влияющих на выполнение операции с семафором. В этом поле может быть установлен флаг IPC_NOWAIT, который предписывает соответствующей операции над семафором не блокировать процесс, а сразу возвращать управление из вызова semop(). Вызов semop() в такой ситуации вернет –1. Кроме того, в этом поле может быть установлен флаг SEM_UNDO, в этом случае система запомнит изменение значения семафора, произведенные данным вызовом, и по завершении процесса автоматически ликвидирует это изменение. Это предохраняет от ситуации, когда процесс уменьшил значение семафора, начав работать с ресурсом, а потом, не увеличив значение семафора обратно, по какой-либо причине завершился. В этом случае остальные процессы, ждущие доступа к ресурсу, оказались бы заблокированы навечно.