Sdílená paměť
Sdílená pamět je jedním z nejjednoduších řešení komunikace mezi procesy. Umožňuje dvěma nebo více procesům sdílet tutéž paměť tak, jako by ji mohly alokovat voláním funkce malloc(). Když jeden proces změní paměť, je tato změna viditelná i pro ostatní procesy.
Sdílená paměť představuje nejrychlejší prostředek pro komunikaci mezi procesy, protože všechny procesy sdílejí tutéž část paměti. Přístup do této paměti je stejně rychlý jako přístup do nesdílené paměti. Protože jádro nesynchronizuje přístup do sdílené paměti, musíte synchronizaci realizovat sami. Nejelegantnějším řešením se jeví řízení pomocí semaforů (příští díl).
Aby bylo možné používat nějaký segment paměti jako sdílený, musí jej jeden proces alokovat. Pak musí každý proces používající tuto paměť získat přístup připojením k paměťovému segmentu. Po skončení používání paměťového segmentu musí každý proces paměť odpojit. Jeden z procesů musí nakonec paměť dealokovat.
Alokace
Alokaci sdíleného paměťového segmentu může proces provést pomocí funkce shmget() (SHared Memory GET). Prvním parametrem funkce je celočíselný klíč specifikující segment, který se má vytvořit. Nespřízněné procesy mohou vytvořit tentýž sdílený segment použitím téže hodnoty klíče. Použití speciální konstanty IPC_PRIVATE jako hodnoty klíče garantuje, že bude vytvořen nový segment paměti (tj. nebudete alokovat sdílenou pamět jiného procesu).
Druhý parametr funkce specifikuje počet bytů v segmentu. Protože jsou segmenty alokovány pomocí stránek, počet skutečně alokovaných bytů je zaokrouhlen na celočíselný násobek velikosti stránky (velikost stránky získáte pomocí funkce getpagesize()).
Třetí parametr specifikuje volby funkce shmget(). V parametru se nastavují bity a může mít tyto hodnoty:
- IPC_CREAT – bude vytvořen nový segment paměti.
- IPC_EXCL – nevytvoří se nový segment, pokud se použije již existující klíč. Tak se zajistí pro volající procesy, že budou přistupovat k výlučnému segmentu. Když druhý parametr není definován a použije se existující segment, funkce shmget() vrátí existující segment a nevytvoří nový.
- Mód – tato hodnota je tvořena devíti bity indikujícími přístupová práva k segmentu pro vlastníka, skupinu a ostatní uživatele. Přístupová práva se snadno specifikují pomocí konstant definovaných v sys/stat.h.
Např.:
int segment_id = shmget(shm_key, getpagesize(), IPC_CREAT | S_IRUSR | S_IWUSR);
Pokud je volání úspěšné, funkce vrátí identifikátor segmentu. Jestliže segment sdílené paměti již existuje, provede se kontrola přístupových práv a také se zkontroluje, zda není segment označen pro destrukci.
Připojení a odpojení
Pomocí funkce shmat()(SHared Memory ATtach) si může každý proces sdílený paměťový segment zpřístupnit. Funkci se předává identifikátor paměťového segmentu SHMID vrácený funkcí shmget(). Druhým argumentem je ukazatel, který specifikuje, kde ve vašem adresovém prostoru chcete mapovat sdílenou paměť. Použijete-li hodnotu NULL, systém vybere nějakou dostupnou adresu. Třetím argumentem je příznak, který může obsahovat následující informace:
- SHM_RND – indikuje, že adresy specifikované pro druhý parametr by měly být zaokrouhleny směrem dolů na násobek velikosti stránky.
- SHM_RDONLY – indikuje, že segment bude určen pouze pro čtení.
Pokud volání funkce skončí úspěšně, vrátí funkce adresu připojeného sdíleného segmentu. Podřízené procesy automaticky sdílejí připojené paměťové segmenty (odpojit je mohou dle potřeby).
Odpojení sdíleného paměťového segmentu je realizováno pomocí funkce shmdt()(SHared Memory DeTach). Jejím argumentem je adresa vrácená funkcí shmat().
Řízení a dealokace sdílené paměti
Funkce shmctl() (SHared Memory ConTroL) vrací informace o sdíleném segmentu a umožňuje jej modifikovat. Prvním parametrem je identifikátor sdíleného paměťového segmentu.
Chcete-li získat informace o segmentu, použijte jako druhý argument IPC_STAT a předejte funkci ukazatel na strukturu struct shmid_ds.
Chcete-li odstranit segment, předejte IPC_RMID jako druhý arguent a jako třetí argument zadejte NULL. Segment se odstraní v okamžiku, kdy se od něj odpojí poslední proces.
Každý sdílený paměťový segment by se měl explicitně dealokovat pomocí funkce shmctl() v okamžiku, kdy paměť přestanete používat. Funkce exit() a exec() totiž paměťové segmenty odpojí, ale ponechají je alokovány.
#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;
/* Alokovani sdileneho pametoveno segmentu */
sgment_id = shmget(IPC_PRIVATE, shared_segment_size, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
/* Pripojeni sdileneho segmentu */
shared_memory = (char *) shmat(segment_id, NULL, NULL);
printf("sdilena pamet byla pripojena na adresu %p\n", shared_memory);
/* Urceni velikosti segmentu */
shmctl(segment_id, IPC_STAT, &shmbuffer);
segment_size = shmbuffer.shm_segsz;
printf("velikost segmentu: %d\n", segment_size);
/* Zapsani retezce do sdileneho pametoveho segmentu */
sprintf(shared_memory, "Hello, world.");
/* Odpojeni pametoveho segmentu */
shmdt(shared_memory);
/* Nove pripojeni sdileneho segmentu( na urcitou adresu) */
shared_memory = (char *) shmat(segment_id, (void *) 0x5000000, NULL);
printf("sdilena pamet byla pripojena na adresu %p\n", shared_memory);
/* Vypis retezce ze sdilene pameti */
printf("%s\n", shared_memory);
/* Odpojeni segmentu */
shmdt(shared_memory);
/* Dealokovani sdileneho pametoveho segmentu */
shmctl(segment_id, IPC_RMID, NULL);
return(0);
}
To by bylo pro dnešek vše, příště se podíváme na řízení přístupu do sdílené paměti pomocí semaforů.