Читать книгу 📗 "Архитектура операционной системы UNIX (ЛП) - Бах Морис Дж."
pint = (int *) addr1; *pint = 256; pint = (int *) addr2; for (i = 0; i ‹ 256, i++) printf("index %dtvalue %dn", i, *pint++); pause();}cleanup() { shmctl(shmid, IPC_RMID, 0); exit();}Рисунок 11.11. Присоединение процессом одной и той же области разделяемой памяти дважды
#include ‹sys/types.h›#include ‹sys/ipc.h›#include ‹sys/shm.h›#define SHMKEY 75#define K 1024int shmid;main() { int i, *pint; char *addr; extern char *shmat(); shmid = shmget(SHMKEY, 64*K, 0777); addr = shmat(shmid, 0, 0); pint = (int *) addr; while (*pint == 0); for (i = 0; i ‹ 256, i++) printf("%dn", *pint++);}Рисунок 11.12. Разделение памяти между процессами

Рисунок 11.13. Структуры данных, используемые в работе над семафорами
Синтаксис вызова системной функции semget:
id = semget(key, count, flag);
где key, flag и id имеют тот же смысл, что и в других механизмах взаимодействия процессов (обмен сообщениями и разделение памяти). В результате выполнения функции ядро выделяет запись, указывающую на массив семафоров и содержащую счетчик count (Рисунок 11.13). В записи также хранится количество семафоров в массиве, время последнего выполнения функций semop и semctl. Системная функция semget на Рисунке 11.14, например, создает семафор из двух элементов.
Синтаксис вызова системной функции semop:
oldval = semop(id, oplist, count);
где id — дескриптор, возвращаемый функцией semget, oplist — указатель на список операций, count — размер списка. Возвращаемое функцией значение oldval является прежним значением семафора, над которым производилась операция. Каждый элемент списка операций имеет следующий формат:
• номер семафора, идентифицирующий элемент массива семафоров, над которым выполняется операция,
• код операции,
• флаги.
#include ‹sys/types.h›#include ‹sys/ipc.h›#include ‹sys/sem.h›#define SEMKEY 75int semid;unsigned int count;/* определение структуры sembuf в файле sys/sem.h struct sembuf { unsigned shortsem_num; short sem_op; short sem_flg;}; */struct sembuf psembuf, vsembuf;/* операции типа P и V */main(argc, argv)int argc;char *argv[];{ int i, first, second; short initarray[2], outarray[2]; extern cleanup(); if (argc == 1) { for (i = 0; i ‹ 20; i++) signal(i,cleanup); semid = semget(SEMKEY, 2, 0777IPC_CREAT); initarray[0] = initarray[1] = 1; semctl(semid, 2, SETALL, initarray); semctl(semid, 2, GETALL, outarray); printf("начальные значения семафоров %d %dn", outarray[0], outarray[1]); pause(); /* приостанов до получения сигнала */ } /* продолжение на следующей странице */ else if (argv[1][0] == 'a') { first = 0; second = 1; } else { first = 1; second = 0; } semid = semget(SEMKEY, 2, 0777); psembuf.sem_op = -1; psembuf.sem_flg = SEM_UNDO; vsembuf.sem_op = 1; vsembuf.sem_flg = SEM_UNDO; for (count = 0; ;count++) { psembuf.sem_num = first; semop(semid, &psembuf, 1); psembuf.sem_num = second; semop(semid, &psembuf,1); printf("процесс %d счетчик %dn", getpid(), count); vsembuf.sem_num = second; semop(semid, &vsembuf, 1); vsembuf.sem_num = first; semop(semid, &vsembuf, 1); }}cleanup() { semctl(semid, 2, IPC_RMID, 0); exit();}Рисунок 11.14. Операции установки и снятия блокировки
Ядро считывает список операций oplist из адресного пространства задачи и проверяет корректность номеров семафоров, а также наличие у процесса необходимых разрешений на чтение и корректировку семафоров (Рисунок 11.15). Если таких разрешений не имеется, системная функция завершается неудачно. Если ядру приходится приостанавливать свою работу при обращении к списку операций, оно возвращает семафорам их прежние значения и находится в состоянии приостанова до наступления ожидаемого события, после чего системная функция запускается вновь. Поскольку ядро хранит коды операций над семафорами в глобальном списке, оно вновь считывает этот список из пространства задачи, когда перезапускает системную функцию. Таким образом, операции выполняются комплексно — или все за один сеанс или ни одной.