Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Совместное использование памяти




В большинстве случаев отдельные вычислительные процессы не общаются друг с другом, выполняя самостоятельную и никак не связанную работу. Но существуют задачи, для решения которых создается не один процесс, а несколько, которые, работая совместно, выполняют общую работу. Такие процессы называются кооперативными.

Для взаимодействия процессов, в частности кооперативных, сложился ряд средств, часть которых – семафоры уже рассматривались, а некоторые будут изучаться в следующих главах. При всем их многообразии следует вспомнить, что основной информационный ресурс, используемый программами – оперативная память – это самый универсальный и быстрый ресурс компьютера. Поэтому не удивительно, что в состав всех современных ОС включены средства использования памяти для взаимодействия независимых процессов. Основой этих средств является разделяемая память, сами средства представляют набор системных функций использования этой памяти, а на более детальном уровне – и информационные средства описания этой памяти.

Изучение средств совместного использования памяти начнем с ОС Unix. Здесь разделяемая память находится под непосредственным управлением ядра, которое содержит таблицу описания областей разделяемой памяти. Каждая из областей обозначается в этой таблице целочисленным идентификатором (а не текстовым именем, как в других ОС). Кроме того, каждая такая область описывается в этой таблице атрибутами доступа и размером. Области разделяемой памяти относятся к адресному пространству ядра ОС.

Доступ к разделяемой памяти со стороны процесса осуществляется в два этапа. На первом из них получается хэндл области памяти, причем на этом этапе либо открывается доступ к уже имеющейся в ОС области памяти, либо такая область создается операционной системой. (Формально ситуация очень напоминает предварительные действия перед непосредственной работой с файлом.) На втором этапе процесс подключается к разделяемой области (to attach), используя ранее полученный хэндл. (Заметим, что сам термин хэндл в первоисточниках по Unix не используется, а применяется термин идентификатор, который в данном тексте действительно точнее. Мы же будем использовать термин хэндл для единообразного рассмотрения средств разделяемой памяти в различных ОС.)

На этапе подключения происходит подсоединение указанной области памяти, находящейся в ведении ОС, к виртуальному адресному пространству процесса, запросившего такое подключение. Результатом этой операции является базовый виртуальный адрес, начиная с которого в текущем процессе можно обращаться к разделяемой памяти.

Для получения разделяемой памяти предназначена функция с прототипом

int shmget(key_t key, int size, int flag),

возвращающая при удачном выполнении целочисленное значение требуемого идентификатора. Первым аргументом этой функции является уникальный номер (внешний идентификатор) области памяти, по своему смыслу аналогичный уникальному имени этого объекта. Вместо решения проблемы уникальности этого значения для новой области разделяемой памяти можно использовать специальную символьную константу IPC_PRIVATE, которая автоматически обеспечит создание внутри вызова уникального идентификатора исключительно для индивидуального пользования текущим процессом и его потомками. Кроме того, в качестве такого обозначения области разделяемой памяти может использоваться значение, полученное в другом процессе и как-то переданное в данный.

Аргумент size задает размер создаваемой по запросу области или ограничение по размеру на уже имеющуюся (больше, чем заданный размер по идентификатору, полученному от функции shmget, использовать будет нельзя). Аргумент flag в простейшем случае задается нулевым, но когда вызывающему процессу нужно создать область с заданным значением key, и области с таким идентификатором нет, то значение этого аргумента должно быть реЧультатом логическЮго сложения симТольной констаЭты IPC_CREAT и прав доступа по чтению и записи к новой области памяти. При неудаче функция возвращает значение -1.

Для подключения процесса к запрошенной ранее области разделяемой памяти служит функция с прототипом

void* shmat(int shmid, void* addr, int flag),

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

При ненулевом аргументе addr последний аргумент может содержать флаг SHM_RND, приказывающий обнулить заданное значение базового адреса до границы страницы. Аргумент flag может также содержать флаг SHM_RDONLY, задающий режим доступа к подключаемой памяти только по чтению. При отсутствии такого флага доступ в дальнейшем будет осуществляться как по чтению, так и по записи. Функция в качестве собственного значения возвращает виртуальный адрес отображения разделяемой памяти, а при неудаче – значение -1.

Для отсоединения разделяемой памяти должна использоваться функция с прототипом

int shmdt(void* addr),

аргументом которой является адрес, ранее полученный от функции shmat. При успешном выполнении она возвращает 0, а при неудаче -1.

Кроме рассмотренных базовых функций для разделяемой памяти, в Unix имеется функция расширенного управления разделяемой памятью с прототипом

int shmctl(int shmid, int cmd, struct shmid_ds *buf).

Первым аргументом этой функции служит идентификатор, полученный от функции shmget. Собственно операции данной функции задаются вторым аргументом, который может задаваться константами IPC_STAT, IPC_SET и IPC_RMID. Первая из них задает операцию получения информации об области разделяемой памяти, вторая – изменение характеристик этой области (изменение прав доступа), а последняя служит для указания освобождения области разделяемой памяти. Третий аргумент используется только с операциями запроса информации и изменения характеристик, а для IPC_RMID задается значением NULL.

 

Следующий пример, приведенный в листинге 10.4.1а и 10.4.1b двумя исходными текстами программ для Unix, демонстрирует рассмотренное построение разделяемой памяти.

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/stat.h>

#include <sys/shm.h>

 

void main()

{char *pm;

int hmem;

 

printf(“Begin work\n”);

hmem=shmget(18011970, 16000, IPC_CREAT | 0600);

if (hmem = = -1)

{perror(“Error AllocSharedMem with:”); getchar(); exit(0);}

pm=shmat(hmem, NULL, 0);

if (pm= =NULL) {perror(“shmat”); exit(3);}

strcpy(pm, “—”);

sleep(8);

strcpy(pm, “Privet Shara!!!”); printf(“Middle work\n”);

sleep(10); printf(“Two step\n”);

strcpy(pm+7, “- Good Bye!!!”); sleep(10);

shmdt(pm);

shmctl(hmem, IPC_RMID, NULL);

exit(0);

}

Листинг 10.4.1а. Первая программа с разделяемой памятью в Unix

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/stat.h>

#include <sys/shm.h>

 

void main()

{char *pb, st[20];

int hmem;

int k;

hmem=shmget(18011970, 16000, 0600);

if (hmem= =-1)

{printf(“Error Shared Get Mem with\n”); getchar(); exit(0);}

pb=shmat(hmem, NULL, SHM_RDONLY);

if (pb= =0)

{printf(“Error Attach Shared Mem\n”); getchar(); exit(0);}

for (k=0;k<10;k++)

{strncpy(st, pb, 20); st[19]=’\0'; printf(“%s\n”, st); sleep(2);}

shmdt(pb);

exit(0);

}

Листинг 10.4.1b. Вторая программа с разделяемой памятью в Unix

 

Вначале следует запускать программу, созданную из исходного текста листинга 10.4.1a, а затем уже программу, созданную из исходного текста по листингу 10.4.1b.

При использовании разделяемой памяти в Linux программисту предоставляется очень удобное системное средство – команда ipcs. Для получения информации о разделяемой памяти эту команду следует вызвать с опцией m, так что весь вызов имеет вид

ipcs -m

Эта команда выводит информацию о присвоенном ключе-идентификаторе, идентификаторе области памяти, владельце, размере и правах доступа к ней.

 

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

HANDLE CreateFileMapping(HANDLE hFile,

//хэндл файла или условное значение

SECURITY_ATTRIBUTES *pFileMappingAttributes,

DWORD protect, // protection for mapping object

DWORD MaxSizeHigh, // high-order 32 bits of object size

DWORD MaxSizeLow, // low-order 32 bits of object size

CTSTR *pName).

Для построения области разделяемой памяти в первом аргументе этой функции должна задаваться специальная константа, равная -1 (обычно задается как (HANDLE)0xFFFFFFFF). Второй аргумент связан с атрибутами защиты и в простейших случаях берется равным нулевому указателю. Четвертый и пятый аргументы в совокупности задают 64-битное значение предельного размера отображаемого объекта, причем в аргументе MaxSizeHigh должны находиться старшие биты этого значения. Для 32-битных версий Windows этот аргумент можно спокойно брать равным нулю. Последний аргумент pName задает имя разделяемой области памяти в нашем текущем рассмотрении или имя области отображения в общем случае. Аргумент protect служит для задания видов доступа к используемой области виртуальной памяти и должен в нашем случае задаваться с помощью константы PAGE_READONLY или PAGE_READWRITE. При невозможности выполнения функция возвращает значение NULL, иначе она предоставляет значение хэндла, через который в дальнейшем возможен доступ к области виртуальной памяти. Заметим, что на этапе, обеспечиваемом рассмотренной функцией, получен только хэндл, но нет информации о базовом адресе виртуальной области памяти, которую с помощью этого хэндла можно использовать. Практически этот этап имеет много общего с действиями фунции shmget из Unix.

Базовый адрес разделяемой памяти получается для использования с помощью функции, имеющий прототип

void* MapViewOfFile(HANDLE hFileMappingObject,

DWORD DesiredAccess,

DWORD OffsetHigh, DWORD OffsetLow, DWORD size),

которая и возвращает требуемый базовый адрес памяти или NULL при невозможности выполнения.

Здесь первый параметр должен быть взят от предыдущего вызова функции CreateFileMapping, предоставляющего хэндл объекта отображения. Третий и четвертый аргументы этой функции совместно задают 64-битное смещение внутри виртуальной области памяти, созданной вызовом функции CreateFileMapping. В большинстве применений это смещение берется нулевым. Аргумент DesiredAccess может задаваться константой FILE_MAP_WRITE или FILE_MAP_READ. Первая задает доступ как по чтению, так и по записи, вторая – только по чтению. Последний аргумент size задает размер разрешенного для дальнейшего использования диапазона виртуальных адресов с заданным видом доступа. Нулевое значение этого аргумента равносильно указанию на использование всего возможного диапазона адресов исходного объекта, созданного функцией CreateFileMapping.

После завершения использования разделяемой памяти для освобождения уже ненужных ресурсов следует вызывать функцию UnmapViewOfFile, имеющую прототип

BOOL UnmapViewOfFile(void* pBaseAddress),

передав ей в качестве аргумента базовый адрес разделяемой памяти. Кроме того, в общем случае следует закрыть хэндл объекта отображаемой памяти с помощью функции CloseHandle.

Следующий пример, приведенный в листинге 10.4.2a и 10.4.2b, демонстрирует применение разделяемой памяти для передачи данных между двумя процессами в Windows.

 

#include <windows.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

 

void main()

{char *pm;

HANDLE hmem;

 

hmem=CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,

PAGE_READWRITE, 0, 16000, “SHAREMEM_MYY”);

if (hmem= =0)

{printf(“Error AllocSharedMem with RC=%ld\n”, GetLastError());

getchar(); exit(0);}

pm=MapViewOfFile(hmem, FILE_MAP_WRITE,0,0,0);

if (pm= =NULL)

{printf(“Error Mapping SharedMem with RC=%ld\n”, GetLastError());

getchar(); exit(0);}

Sleep(4000);

strcpy(pm, “Privet Shara!!!”); printf(“Middle work\n”); Sleep(10000);

printf(“Two step\n”);

strcpy(pm+7, “- Good Bye!!!”); Sleep(10000);

UnmapViewOfFile(pm);

CloseHandle(hmem);

}

Листинг 10.4.2a. Первая программа с разделяемой памятью для Windows

 

#include <windows.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

 

void main()

{char *pb, st[20];

HANDLE hmem;

int k;

hmem=OpenFileMapping(FILE_MAP_READ, FALSE,

“SHAREMEM_MYY”);

if (hmem= =0)

{printf(“Error OpenSharedMem with RC=%ld\n”, GetLastError());

getchar(); exit(0);}

pb=MapViewOfFile(hmem, FILE_MAP_READ,0,0,0);

if (pb= =NULL)

{printf(“Error Mapping SharedMem with RC=%ld\n”, GetLastError());

getchar(); exit(0);}

for (k=0;k<10;k++)

{strncpy(st, pb, 20); st[19]=’\0'; printf(“%s\n”, st); Sleep(2000); }

UnmapViewOfFile(pb); CloseHandle(hmem);

}

Листинг 10.4.2b. Вторая программа с разделяемой памятью для Windows

 

Для демонстрации поведения программ следует вначале запускать программу, созданную из исходного текста в листинге 10.4.2a, а затем уже программу, созданную из исходного текста в листинге 10.4.2b.




Поделиться с друзьями:


Дата добавления: 2014-01-05; Просмотров: 521; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.064 сек.