Sunteți pe pagina 1din 6

Sisteme de Operare Laborator nr.

12

Laborator nr. 12

Memoria partajata

La fiecare dintre metodele de comunicatie intre procese prezentate pina acum,


informatia era transferata intre cele doua procese implicate, adica era copiata in afara
spatiului de adresare al procesului sursa si apoi recopiata in spatiul de adresare al
procesului destinatie, prin intermediul unor apeluri sistem. Acest lucru necesita unele
transformari asupra datelor transferate si uneori, transferarea unor informatii suplimentare.
Atita timp cit cele doua procese comunica, ele trebuie sa se gaseasca deja in memorie
impreuna cu datele lor. Daca datele de transmis se afla deja in memorie, cele doua
procese pot accesa amindoua zona de memorie in care se gasesc datele comune.
Aceasta memorie devine memoria partajata.
Folosirea memoriei partajate ofera o metoda eleganta si rapida de comunicatie intre
cele doua procese care acceseaza in comun o zona de memorie interna. Aceasta zona
poate fi folosita de oricare dintre procesele din sistem care ii cunosc cheia. Pentru fiecare
proces care utilizeaza memoria partajata este necesar ca ea sa se gaseasca in spatiul sau
de adresare. Acest lucru asigura de fapt eficienta maxima, in continuare aceasta zona fiind
accesata ca si o variabila obisnuita, fara folosirea apelurilor sistem.
Folosirea unor zone de memorie in comun de catre doua procese impune desigur si
o serie de restrictii de acces si necesitati de sincronizare care se rezolva de obicei cu
ajutorul semafoarelor. Programarea defectoasa a accesului la memoria partajata a mai
multor procese poate duce usor la blocaje (deadlocks).
Din punctul de vedere al programatorului, principiul de lucru cu memoria partajata
este foarte simplu: un segment de memorie partajata trebuie creat si deschis, apoi atasat
in spatiul de adresare al proceselor care au nevoie de el. Apoi, fiecare dintre procese
poate scrie sau citi fara restrictii din zona respectiva. Cind un proces nu mai are nevoie de
memoria partajata, el poate detasa segmentul. Daca nici unul dintre procese nu mai are
nevoie de el, segmentul de memorie partajata, poate fi eliminat complet. Pentru operatiile
de creare, deschidere, atasare, detasare, eliminare a segmentelor de memorie partajata
exista apeluri ale nucleului. Pentru accesarea datelor din segment nu exista apeluri,
accesul facindu-se prin intermediul pointerilor.
Pentru a adresa segmentele de date procesoarele moderne folosesc un registru de
segmentare. Daca este disponibil un astfel de registru, implementarea memoriei partajate
este foarte usoara (acest lucru este rezolvat de cei care implementeaza UNIX-ul si nu de
catre cei care folosesc memoria partajata in aplicatii!). Accesul ulterior la acest segment se
face aproape la fel de repede ca la orice variabila locala a procesului, de aceea memoria
partajata este de departe cea mai rapida metoda de comunicatie intre procese comparativ
cu metodele prezentate pina acum.
Desigur, hardware-ul poate sa impuna si limitari. De exemplu numarul de segmente
de memorie partajata care pot fi folosite deodata de catre un proces este dependent de
arhitectura sistemului. Daca se doreste ca aplicatiile sa ramina portabile, nu trebuie folosit
decit un singur element de memorie partajata. La fel hardware-ul determina si marimea
maxima a unui segment. De obicei un minim de 64K este disponibil.
Pentru crearea si deschiderea unui segment de memorie partajata exista apelul
sistem shmget. Se apeleaza in felul urmator:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

key_t cheie;
int marime, permisii, shmid;
...
Sisteme de Operare Laborator nr. 12
shmid=shmget(cheie, marime, permisii);
...
La fel ca si la mesaje, cel mai important parametru este primul, cheie, cel care da
cheia de recunoastere globala a segmentului. Orice alt proces care vrea sa foloseasca
segmentul de memorie partajata, creat cu shmget, trebuie sa cunoasca aceasta cheie.
Cheia este, ca si mai inainte, de tipul key_t, dependent de implementare, dar de obicei un
long. Al doilea parametru, marime, este cel care specifica dimensiunea in octeti a
segmentului de memorie partajata care se doreste a fi cret. Ultimul parametru, permisii,
specifica drepturile de acces la segment. Apelul returneaza in shmid un identificator al
segmentului nou creat, care este local procesului. Daca apelul esueaza in crearea
segmentului de memorie partajata, este intoarsa valoarea -1, iar eroarea va fi
documentata in variabila globala errno. Valorile de eroare din errno sint dependente de
implementare. Trebuie consultat manualele on-line pentru functia shmget(S).
Daca marimea specificata la apel pentru segment este prea mare sau prea mica,
errno va fi setat pe valoarea EINVAL. Ce inseamna prea mic sau prea mare pentru
implementarea data, trebui de asemenea aflat.
Pentru specificarea permisiilor, se pot folosi valori asemanatoare cu cele pentru cozi
de mesaje. Trebuie deci specificate drepturile de acces la segment si citiva comutatori de
creare. De exemplu poate primi valoarea 066 | IPC_CREAT | IPC_EXCL, deci drepturi de
citire/scriere doar pentru proprietar, segmentul de memorie partajata va fi deschis numai
daca nu exista deja, caz in care va fi mai intai creat. Daca segmentul exista deja se va
intoarce valoarea de eroare -1.
Prin acest apel, a fost creat in memorie segmentul dorit. Accesul la el se va face in
continuare prin intermediul identificatorului sau, shmid. Acesta este local procesului
curent, deci nu va avea aceasi valoare si pentru alte procese care deschid aceeasi zona
de memorie partajata. La terminarea acestui apel segmentul nu este inca gata de a fi
folosit pentru procesul curent. Aceasta din cauza ca segmentul nu se gaseste inca in
spatiul de adresare al procesului. Pentru a atasa segmentul de memorie la proces exista
apelul shmat (attach shared memory). El poate fi apelat dupa cum urmeaza:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int comutatori,shmid;
char *adresa,*adresa_impusa;
...
adresa=shmat(shmid, adresa_impusa, comutatori);
...

Prin acest apel se creaza pentru procesul curent o adresa virtuala cu care se va
putea adresa in continuare zona de memorie partajata. Variabila adresa va contine dupa
apel aceasta adresa. Prin apel se poate forta si legarea segmentului la o anumita adresa
dorita, specificata prin parametrul adresa_impusa. Daca acest parametru are valoarea 0
si acesta este cazul comun, atunci sistemul va decide singur care este adresa unde va fi
legat segmentul si aceasta va fi urmatoarea adresa disponibila.
Se poate de asemenea impune ca segmentul sa fie atasat la o adresa care sa fie
inceput de pagina de memorie. Pentru aceasta trebuie specificata valoarea SHM_RND in
parametrul comutatori. Daca se impune o adresa de atasare, aceasta va fi rotunjita la
urmatorul inceput de pagina. Daca nu, va fi intors urmatorul inceput de pagina. Daca nu,
va fi intors urmatorul inceput de pagina disponibil. Alt comutator disponibil este
SHM_RDONLY, care specifica faptul ca segmentul trebuie protejat la scriere. Din pacate
numai acele configuratii hardware pot asigura o astfel de protectie. Daca parametrul
comutatori are valoarea 0, atunci accesul este si in citire si in scriere iar adresa nu va fi
Sisteme de Operare Laborator nr. 12
rotunjita in nici un fel.
Din acest moment acesul la segmentul de memorie este posibil prin adresa virtuala
adresa. Se poate scrie si citi din memorie variabile intregi prin instuctiuni de genul:

int i, *pint;

pint=(int *)adresa;
*pint++=i;
...
i=*pint;
...
Sau se poate adresa segmentul caracter cu caracter in felul urmator:

int i;

for(i=0;adresa[i];i++)
...;
Dupa terminarea lucrului cu memoria partajata aceasta trebuie desigur eliminata din
spatiul de adresare al procesului. Acest lucru se face cu ajutorul apelului shmdt (detach
shared memory). Acesta se apeleaza astfel:

...
retur=shmdt(adresa);
...

Dupa acest apel nu se mai poate adresa in nici un fel segmentul de memorie
partajata, decit dupa o noua atasare. In clipa in care toate procesele care aveau nevoie de
segmentul de memorie partajata s-au detasat de la acesta, segmentul poate fi distrus
complet printr-un apel shmctl. Apelarea se face astfel:

...
retur=shmctl(shmid, IPC_RMID, 0);
...

Trebuie acordata foarte mare atentie la distrugerea unui segment de memorie


partajata. Daca mai exista procese care au atasat acel segment pot apare erori foarte
grave, care sa duca chiar la caderea sistemului !
Sistemele de tip Linux/Unix pun la dispozitie comanda ipcs ce permite vizualizarea
informatiilor legate de comunicatiile interproces (se foloseste cu parametrul -m pentru
memoria comuna):

$ ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 1627649 user 640 25600 0

Pentru a sterge zona de memorie afisata mai sus se foloseste comanda ipcrm:

$ ipcrm shm 1627649

Exemplul 1: Urmatorul program se poate urmari fara explicatii suplimentare. In


program memoria partajata este atasata si detasata la fiecare acces. Acest lucru nu este
in general necesar si trebuie evitat pe cit posibil datorita pierderii de viteza. Aceasta
limitare nu mai este valabila in implementarile moderne.
Sisteme de Operare Laborator nr. 12
/* shmem.h */

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHMKEY (key_t)100

/* scrie.c */

#include "shmen.h"
int shmid;
main()
{
int i;
char *adresa;
extern cleanup();

/*Captarea tuturor semnalelor*/


for(i=0;i < 20;i++)
signal(i, cleanup);
/*crearea zonei de memorie partajata*/
/*marimea este de 4096 octeti*/
/*identificator SHMKEY*/
shmid=shmget(SHMKEY, 4096, 0660|IPC_CREAT);

i=0;
while(1)
{
/*legarea in spatiul de adrese*/
adresa=shmat(shmid, 0, 0);

/*scrierea mesajului in memoria partajata*/


sprintf(adresa, "%6d hello,world!",i++);

/*dezlegarea din spatiul de adrese*/


shmdt(adresa);
}
}
cleanup()
{
shmctl(shmid, IPC_RMID, 0);
exit();
}

/* citeste.c */

#include "shmen.h"
int shmid;
main()
{
int i,*pint=0;
char *adresa;

/*deschiderea zonei de memorie partajata*/


shmid=shmget(SHMKEY, 2048, 0660);

for(i=0;i < 20;i++) {


/*legarea la spatiul de adresare*/
adresa=shmat(shmid, 0, 0);

while(*pint==0);
/*nu citeste pina nu este gata driverul*/
Sisteme de Operare Laborator nr. 12

/*citirea mesajului*/
printf("%s\n",adresa);

/*dezlegarea din spatiul de adresare*/


shmdt(adresa);
sleep(1);
}
}

Exemplul 2:
#include <stdio.h>
#include <sys/shm.h>
#include <sys/stat.h>
int main ()
{
int segment_id;
char* shared_memory;
struct shmid_ds shmbuffer;
int segment_size;
const int shared_segment_size = 0x6400;

/* Allocate a shared memory segment. */


segment_id = shmget (IPC_PRIVATE, shared_segment_size, IPC_CREAT |
IPC_EXCL | S_IRUSR | S_IWUSR);
/* Attach the shared memory segment. */
shared_memory = (char*) shmat (segment_id, 0, 0);
printf (“shared memory attached at address %p\n”, shared_memory);
/* Determine the segment’s size. */
shmctl (segment_id, IPC_STAT, &shmbuffer);
segment_size = shmbuffer.shm_segsz;
printf (“segment size: %d\n”, segment_size);
/* Write a string to the shared memory segment. */
sprintf (shared_memory, “Hello, world.”);
/* Detach the shared memory segment. */
shmdt (shared_memory);
/* Reattach the shared memory segment, at a different address. */
shared_memory = (char*) shmat (segment_id, (void*) 0x5000000, 0);
printf (“shared memory reattached at address %p\n”, shared_memory);
/* Print out the string from shared memory. */
printf (“%s\n”, shared_memory);
/* Detach the shared memory segment. */
shmdt (shared_memory);
/* Deallocate the shared memory segment. */
shmctl (segment_id, IPC_RMID, 0);
return 0;
}

Bibliografie:
• Iosif Ignat, Adrian Kacso, UNIX Gestionarea Proceselor, Ed. Albastră, 2006
• W. Richard Stevens, Stephen A. Rago, Advanced Programming in the UNIX Envi-
ronment: Second Edition, Addison Wesley, 2005
• Kurt Wall, Mark Watson, and Mark Whitis, Linux Programming Unleashed, Sams
Publishing, 1999
• A. D. Marshall, Programming in C. UNIX System Calls and Subroutines using C,
http://www.cs.cf.ac.uk/Dave/C/
• Guide to Unix IPC http://beej.us/guide/bgipc/output/html/singlepage/bgipc.html
Sisteme de Operare Laborator nr. 12
• Mark Mitchell, Jeffrey Oldham, and Alex Samuel, Advanced Linux Programming,
New Riders Publishing, 2001, http://www.advancedlinuxprogramming.com/
• Compiler, assembler, linker and loader: a brief story
http://tenouk.com/ModuleW.html

S-ar putea să vă placă și