Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛР5.docx
Скачиваний:
15
Добавлен:
12.02.2016
Размер:
400.53 Кб
Скачать

Робота з розподіленою пам'яттю

Для роботи з пам'яттю, що розділяється використовуються системні виклики:

  • shmget створює новий сегмент розподіленої пам'яті або знаходить існуючий сегмент з тим самим ключем;

  • shmat підключає сегмент із зазначеним описувачем до віртуальної пам'яті процесу, що здійснює звернення;

  • shmdt відключає від віртуальної пам'яті раніше підключений до неї сегмент із зазначеною віртуальною адресою початку;

  • shmctl служить для управління різноманітними параметрами, пов'язаними з існуючим сегментом.

Прототипи перерахованих системних викликів описані в файлах

#include <sys / ipc.h>

#include <sys / shm.h>

Після того як сегмент розподіленої пам'яті підключений до віртуальної пам'яті процесу, цей процес може звертатися до відповідних елементів пам'яті з використанням звичайних машинних команд читання і запису.

Системний виклик

int shmid = shmget (key_t key, size_t size, int flag)

на підставі параметру size визначає бажаний розмір сегменту в байтах. Якщо в таблиці розподіленої пам'яті знаходиться елемент, що містить заданий ключ, і права доступу не суперечать поточним характеристикам процесу, що здійснює звернення, то значенням системного виклику є ідентифікатор існуючого сегменту, причому параметр size повинен бути в цьому випадку рівним 0. В іншому випадку створюється новий сегмент з розміром не менше встановленого в системі мінімального розміру сегменту розподіленої пам'яті і не більше встановленого максимального розміру. Живучість об'єктів розподіленої пам'яті визначається живучістю ядра. Створення сегменту не означає негайного виділення під нього основної пам'яті, і ця дія відкладається до виконання першого системного виклику підключення сегменту до віртуальної пам'яті деякого процесу. Прапори IPCCREAT і IPCEXCL аналогічні розглянутим вище.

Підключення сегменту до віртуальної пам'яті виконується шляхом звернення до системного виклику shmat

void * virtaddr = shmat (intshmid, void * daddr, int flags)

Параметр shmid – це раніше отриманий ідентифікатор сегменту, a daddr – бажана процесом віртуальна адреса, яка повинна відповідати початку сегменту в віртуальній пам'яті.

Значенням системного виклику є фактична віртуальна адреса початку сегменту. Якщо значенням daddr є NULL, ядро вибирає найбільш зручну віртуальну адресу початку сегмента. Прапори системного виклику shmat наведені нижче в таблиці.

Прапори системного виклику shmat

Прапорець

Опис

SHM_RDONLY

Ядро підключає ділянку пам'яті тільки для читання

SHM_RND

Визначає, якщо можливо, спосіб обробки ненульового значення daddr.

Для відключення сегменту від віртуальної пам'яті використовується системний виклик shmdt:

int shmdt (* daddr)

де daddr – це віртуальна адреса початку сегменту у віртуальній пам'яті, раніше отриманий від системного виклику shmat.

Системний виклик shmctl

int shmctl (int shmid, int command, struct shmid_ds * shrn_stat)

по синтаксису і призначенню аналогічний msgctl.

Приклади практичної реалізації Розподілена пам’ять.

Програма shmget створює сегмент розподіленої пам'яті, приймаючи з командного рядка повне ім'я довільного файлу і довжину сегмента.

#include <stdio.h>

#include <error.h>

#include <fcntl.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#include <unistd.h>

#include <stdlib.h>

#define SVSHM_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

int main(int argc, char**argv)

{

int c, id, oflag;

сhar *ptr;

size_tlength;

oflag= SVSHM_MODE| IPC_CREAT; // прапорець створення семафора

while ( (c = getopt(argc, argv, "e")) != -1) {

switch(c) { // перегляд ключів командного рядка

case'e':

oflag|= IPC_EXCL;

break;

}

}

if (optind != argc -2)

{

printf("usage: shmget [ -e ] <path_to_file> <length>");

return 0;

}

length = atoi(argv[optind + 1]);

id = shmget(ftok(argv[optind], 0), length, oflag);

ptr= (char*) shmat(id, NULL, 0);

return0;

}

Виклик shmget створює сегмент розподіленої пам'яті зазначеного розміру. Повне ім'я, передане в якості аргументу командного рядка, перетвориться в ключ IPC System V викликом функції ftok. Якщо вказано параметр е командного рядка і в системі існує сегмент з тим самим ім'ям, запуски програми завершаться помилкою. Якщо відомо, що сегмент вже існує, то в командному рядку повинна бути вказана нульова довжина сегмента пам'яті.

Виклик shmat підключає сегмент до адресного простору процесу, після чого програма завершує роботу. У зв'язку з тим, що розподілена пам'ять System V володіє «живучістю ядра», то сегмент розподіленої пам'яті при цьому не видаляється.

Програма shmrmid викликає функцію shmctl з командою IPC_RMID для видалення сегменту розподіленої пам'яті з системи

#include <stdio.h>

#include<sys/ipc.h>

#include <sys/shm.h>

#include <error.h>

#include <fcntl.h>

#define SVSHM_MODE(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

int main(int argc, char **argv)

{

int id;

if (argc != 2)

{

printf("usage: shmrmid <path_to_file>");

return 0;

}

id = shmget(ftok(argv[1], 0), 0, SVSHM_MODE);

shmctl(id, IPC_RMID, NULL);

return0;

}

Програма shmwrite заповнює сегмент розподіленої пам'яті послідовністю значень 0, 1, 2, ..., 254, 255. Сегмент розподіленої пам'яті відкривається викликом shmget і підключається викликом shmat. Його розмір може бути отриманий викликом shmctl з командою IPC_STAT.

#include <stdio.h>

#include<sys/ipc.h>

#include <sys/shm.h>

#include <error.h>

#include <fcntl.h>

#define SVSHM_MODE(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

int main(int argc, char **argv)

{

int i, id;

struct shmid_ds buff;

unsigned char *ptr;

if (argc != 2)

{

printf("usage: shmwrite <path_to_file>");

return 0;

}

id = shmget(ftok(argv[1], 0), 0, SVSHM_MODE);

ptr = (unsigned char*) shmat(id, NULL, 0);

shmctl(id, IPC_STAT, &buff);

/* 4set: ptr[0] = 0, ptr[1] = 1, etc. */

for (i = 0; i < buff.shm_segsz; i++) *ptr++ = i % 256;

return0;

}

Програма shmread перевіряє послідовність значень, записану в пам'ять, що розділяється програмою shmwrite.

#include<stdio.h>

#include <unistd.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#include<error.h>

#include <fcntl.h>

#define SVSHM_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

int main(int argc, char **argv)

{

int i, id;

struct shmid_ds buff;

unsigned char c, *ptr;

if (argc != 2)

{

printf("usage: shmread <path_to_file>");

return 0;

}

id = shmget(ftok(argv[1], 0), 0, SVSHM_MODE);

ptr = (unsigned char*) shmat(id, NULL, 0);

shmctl(id, IPC_STAT, &buff);

/* check that ptr[0] = 0, ptr[1] = 1, and so on. */

for (i = 0; i < buff.shm_segsz; i++)

if ( (c = *ptr++) != (i % 256)) printf("ptr[%d] = %d", i, c);

return0;

}

Розглянемо результат запуску наведених вище програм при роботі з пам'яттю. На початку створюється сегмент розподіленої пам'яті довжиною 1234 байта. Для ідентифікації сегменту використовуємо повне ім'я виконуваного файлу / tmp / test1. Це ім'я буде передано функції ftok

shmget/tmp/test1 1234

ipcs -bmo

IPC status from <running system> as of Thu Jan 8 13:17:06 1998

T ID KEY MODE OWNER GROUP NATTCH SEGSZ

Shared Memory:

m 1 0x0000fl2a --rw-r--r--rstevens otherl 0 1234

Програма ipcs запускається для того, щоб переконатися, що сегмент розподіленої пам'яті дійсно був створений і не був видалений при завершенні програми shmcreate.

Запускаючи програму shmwrite можна заповнити вміст розподіленої пам'яті послідовністю значень. Потім за допомогою програми shmread перевіряється вміст сегмента розподіленої пам'яті

shmwrite shmget

shmread shmget

shmrmid shmget

ipcs -bmo

IPC status from <running system> as of Thu Jan 8 13:17:06 1998

T ID KEY MODE OWNER GROUP NATTCH SEGSZ

Shared Memory:

Видалити пам'ять, що розділяється можна викликавши

shmrmid/tmp/test1

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]