Osztott memória (shared memory)
Alkalmazása esetén ugyanazt a memóriarészt használja az összes összeköttetésben levő folyamat...
Műveletek
az osztott memóriával
Az
osztott memória adatainak lekérdezése, módosítása és törlése(shmctl)
Memóriarész
hozzárendelése(shmat)
Memóriarész
hozzárendelésének megszüntetése(shmdt)
Műveletek az osztott memóriával
Osztott
memória eltávolítása (shm_unlink());
Adatok memóriába
ágyazása(mmap())
Memória
felszabadítása(munmap())
Hozzáférés
módosító(mprotect())
Az osztott vagy közös memória segítségével megoldható, hogy két vagy több folyamat
ugyanazt a memóriarészt használja. Az osztott memóriazónák általi kommunikáció
elvei:
- Egy folyamat létrehoz egy közös memóriazónát. A folyamat azonosítója
bekerül a memóriazónához rendelt struktúrába.
- A létrehozó folyamat hozzárendel az osztott memóriához egy numerikus
kulcsot, amelyet minden ezt a memóriarészt használni kívánó folyamatnak
ismernie kell. Ezt a memóriazónát az shmid
változó azonosítja.
- A létrehozó folyamat leszögezi a többi folyamat hozzáférési jogait az
illető zónához. Azért, hogy egy folyamat (beleértve a létrehozó folyamatot
is) írni és olvasni tudjon a közös memóriarészből, hozzá kell rendelnie
egy virtuális címterületet.
Ez a kommunikáció a leggyorsabb, hiszen az adatokat nem kell mozgatni a
kliens és a szerver között.
A folyamatoknak a közös memóriarészhez való hozzáférését nem a rendszer
felügyeli, a konfliktusok kezelése a felhasználó folyamatok feladata. Ha a
szerver adatokat helyez el a közös memóriarészben, akkor a kliensnek várakoznia
kell egészen a művelet befejezéséig, s csak akkor férhet hozzá az
illető adatokhoz. A hozzáférések összehangolására gyakran használunk
szemaforokat.
A rendszer minden egyes közös memóriarész esetén a következő adatokat
tárolja:
struct shmid_ds
{
struct ipc_perm shm_perm; /* definiálja
a jogokat és a tulajdonost */
struct anon_map *shm_amp; /* pointer a rendszerben*/
int
shm_segz;
/* szegmens mérete bájtokban*/
pid_t
shm_cpid; /* létrehozó folyamat pid-je*/
pid_t
shm_lpid; /* utolsó shmop() pid-je*/
ulong shm_nattach; /* eddig kapcsolódót folyamatokszáma*/
ulong shm_cnattch; /* csak az shminfo használja*/
time_t
shm_atime; /* utolsó beírás ideje*/
time_t
shm_dtime; /* utolsó kiolvasás ideje*/
time_t shm_ctime;
/* utolsó struktúramódosítás ideje*/
}
Egy folyamat csak akkor férhet hozzá a közös memóriarészhez ha:
- a folyamat a superuser-é,
- a felhasználó ID-je (uid) megegyezik az shm_perm.cuid-vel
vagy az shm_perm.uid-vel és az shm_perm.mode tartalmazza a kívánt jogokat,
- a felhasználó csoportazonosítója (gid) megegyezik az shm_perm.cgid
vagy shm_perm.gid értékek egyikével és az shm_perm.mode tartalmazza a kívánt jogokat,
- a felhasználó beleesik a "többi
felhsználó" kategóriába és az shm_perm.mode
tartalmazza a megfelelő jogokat.
Műveletek az osztott memóriával
Létrehozás (shmget)
Az shmget rendszerfüggvény engedélyezi a közös
memória azonosítójának lekérdezését felhasználva egy bizonyos kulcsot. Alakja:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, int size,
int flg);
A függvény visszatérési értéke a key
kulcshoz rendelt memóriazóna azonosítója, illetve -1 hiba esetén. A size változóban a közös memória méretét kell megadni,
míg az flg-ben a létrehozási tevékenységet és a
hozzáférési jogokat. A kulcsot a közös memóriát használó összes folyamatnak
kell ismernie.
Egy új memóriaterület létrehozása esetén az flg mezőt a következő formában kell
megadni:
IPC_CREAT
| IPC_EXCL | hozzáférési_jogok
Ha az IPC_CREAT opció nincs beállítva, és
már létezik egy előzőleg létrehozott memóriazóna, a függvény ennek az
azonosítóját téríti vissza.
Példaként hozzunk létre egy 2003 kulccsal rendelkező 200 bájt
méretű memóriarészt.
#define KEY 2003
int shmid;
shmid = shmget((key_t) KEY, 200, IPC_CREAT | 0666);
Ha egy már létező osztott memóriarész azonosítóját (ID-ját) szeretnénk
meghatározni, akkor a size és az flg mezőbe 0-t írunk – ez esetben a függvény nem
fog létrehozni új sort. Például az előzőleg létrehozott memóriazóna
esetén a következőképpen járunk el:
shmid = shmget((key_t) KEY, 0,
0);
Létrehozáskor a társított adatstruktúra (shm_perm) mezői a következő információkkal
töltődnek fel:
- shm_perm.cuid,
shm_perm.uid– az shmget függvényt meghívó
folyamathoz hozzárendelt felhasználó ID-ja,
- shm_perm.cgid, shm_perm.uid–
az shmget függvényt meghívó folyamathoz hozzárendelt felhasználócsoport ID-ja,
- shm_perm.mode– az shmget függvény hívásakor
megadott flg argumentum, amely a hozzáférési jogokat tartalmazza,
- shm_qnum, shm_lspid,
shm_lrpid, shm_stime,
shm_rtime – értéke 0,
- shm_ctime– az aktuális időt
tartalmazza,
- shm_segz– az shmget függvény hívásakor
megadott size argumentum.
Előfordulhat, hogy egy osztott
memóriazónának nincs hozzárendelt kulcsa. Ebben az esetben a key paraméternek az IPC_PRIVATE értéket adjuk.
Az osztott memória adatainak lekérdezése, módosítása
és törlése (shmctl)
Az shmctl függvény az osztott memóriarész
információinak lekérdezésére, módosítására és törlésére használható.
Szintaxisa:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd,
struct shmid_ds *buf);
A függvény visszatérési értéke 0, ha a művelet sikeres volt,
ellenkező esetben -1. Az shmid
paraméter az shmget függvény által meghatározott osztott
memóriarész azonosítója.
A cmd argumentum a kívánt műveletet
határozza meg és a következő értékeket veheti fel:
- IPC_STAT – az osztott memóriához rendelt struktúra
tartalma a buf változóba kerül,
- IPC_SET – az osztott memóriához rendelt struktúrát
frissíti a buf által megadott struktúrával,
- IPC_RMID – az osztott memóriarész elméletileg
törlődik; a tulajdonképpeni törlésre csak akkor kerül sor, amikor az
utolsó folyamat is, amely ezt a zónát használja, megszakítja a kapcsolatát
ezzel a memóriarésszel; függetlenül attól, hogy ez a rész éppen használat alatt
van-e vagy sem az ID törlődik, s ezáltal ez a memóriarész többet nem
osztható ki egyetlen folyamat számára sem; ebben az esetbe a buf argumentumnak a NULL értéket kell adni,
- SHM_LOCK – megtiltja a hozzáférést a közös
memóriarészhez,
- SHM_UNLOCK
– engedélyezi a hozzáférést a közös memóriarészhez.
Példa:
#define KEY 2003
shmid = shmget((key_t) KEY, 0,
0);
shmctl(shmid, IPC_RMID, NULL);
Memóriarész hozzárendelése (shmat)
Az shmat függvény feladata egy folyamat
címterületéhez hozzárendelni egy osztott memóriazónát. A hozzárendelés után a
folyamat írhat, illetve olvashat erről a memóriarészről. A függvény
szintaxisa:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
void *shmat(int shmid, void
*addr, int flg);
A függvény visszatérített értéke egy pointer a közös memóriazónára, ha a
művelet sikeres volt, ellenkező esetben -1. Az shmid paraméter az shmget által meghatározott osztott memória azonosítója.
A addr pointer típusú változó a közös
memóriarész hozzáférési címe a hívó folyamat adatszegmensében. Ezért ha:
- ha az addr
≠ NULL, a
következő esetek fordulnak elő:
a. ha az SHM_RND opció be van állítva, a
hozzárendelés az addr címhez történik,
b. ha az SHM_RND nincs beállítva, a
hozzárendelés az (addr - (addr mod SHMLBA))
címhez történik,
- ha az addr
= NULL, a memóriarész a rendszer által kiválasztott első szabad címhez
történik (ajánlott).
Az flg paraméter meghatározza a hozzárendelt
memória megadási módját (SHM_RND) és a közös részhez való hozzáférést, tehát
hogy írásvédett (SHM_RDONLY) vagy sem.
A következő példa bemutatja, hogyan lehet írni egy közös
memóriazónára:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#define KEY 2003
void main(void)
{
int shmid;
char *p;
...
shmid = shmget((key_t) KEY, 0, 0);
p = shmat(shmid, NULL, 0);
strcpy(p, "proba");
...
exit(0);
}
Memóriarész hozzárendelésének megszüntetése (shmdt)
Az shmdt függvény feladata a hívó folyamat
címterületéhez hozzárendelt osztott memóriazóna felszabadása. Megjegyezzük,
hogy a memóriarészhez hozzárendelt struktúra és az ID nem törlődik a
rendszerből, míg egy folyamat (általában a szerver) az shmctl függvényhívással (IPC_RMID) azt végérvényesen
nem törli. Alakja:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmdt(void *addr);
A következő programrészlet bemutatja, hogyan lehet kiolvasni adatokat
egy olyan közös memóriazónából, ahová előzőleg egy másik folyamat
írt. A végén a memóriaterületet felszabadítjuk és töröljük.
#include <stdio.h>
#include <sys/type.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define KEY 2003
void main(void)
{
int shmid;
char *p;
...
shmid = shmget((key_t) KEY, 0, 0);
p = shmat(shmid, NULL, 0);
printf("a kozos memoria tartalma: %s\n", p);
shmdt(p);
shmctl(shmid, IPC_RMID, NULL);
exit(0);
}
Készítsünk olyan programot, amely létrehozza, olvassa, írja és törli az
osztott memóriát! A műveletet a parancssoron keresztül fogjuk megadni.
Amennyiben egy művelet kiadásakor a közös memória nem létezik a program
automatikusan hozza létre azt!
A folyamat tehát a következő műveleteket tudja elvégezni:
- írás a memóriazónába: shmtool w "text"
- a memóriazónán található szöveg kiolvasása: shmtool r
- a hozzáférési jogok módosítása (mode): shmtool m (mode)
- memóriarész törlése: shmtool r
A forráskód tartalmazza a főprogramot és a műveleteket
elvégző segédeljárásokat. (Az ftok
utasítással a folyamat számára egyedi kulcsot hozunk létre.)
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SEGSIZE
100
/* a
tárolandó szöveg max. mérete */
void writeshm(int shmid, char
*segptr, char *text);
void readshm(int shmid, char *segptr);
void removeshm(int
shmid);
/* függvények
deklarálása*/
void changemode(int shmid, char *mode);
void usage(void);
int main(int argc, char
*argv[])
/* parancssorból
a paraméterek*/
{
key_t
key;
/* kulcs*/
int
shmid;
/* osztott
memória ID-ja*/
char
*segptr;
/* osztott
memória címe*/
if (argc == 1)
usage();
/* hiányos
paraméterlista*/
key = ftok(".",
'S');
/* egyedi
kulcs létrehozása*/
/* megnyitás,
szükség esetén létrehozás */
if ((shmid = shmget(key,
SEGSIZE, IPC_CREAT|IPC_EXCL|0666)) == -1)
{
printf("az osztott memoriazona letezik -
megnyitom\n");
if ((shmid =
shmget(key, SEGSIZE, 0)) == -1)
{
perror("shmget hiba");
exit(1);
}
}
else
printf("letrehozok egy uj osztott
memoriazonat\n");
/* memóriacím
hozzárendelése*/
if ((segptr = shmat(shmid,
0, 0)) == (void *) -1)
{
perror("shmat hiba");
exit(1);
}
switch
(tolower(argv[1][0]))
/* a
param. alapján elvégzi a műv.*/
{
case
'w':
/* megadott
szöveg írása*/
writeshm(shmid, segptr, argv[2]);
break;
case
'r':
/* osztott
memóriazóna kiolvasása*/
readshm(shmid, segptr);
break;
case
'd':
/* törlés*/
removeshm(shmid);
break;
case
'm':
/* jogok
módosítása*/
changemode(shmid, argv[2]);
break;
default:
/* hibás
opció*/
usage();
}
}
void writeshm(int shmid, char
*segptr, char *text)
{
strcpy(segptr,
text);
/* szöveg
beírása a memóriába */
printf("kesz...\n");
}
void readshm(int shmid, char
*segptr)
{
printf("segptr: %s\n",
segptr);
/* mem.
tartalmának kiolvasása*/
}
void removeshm(int shmid)
{
shmctl(shmid, IPC_RMID,
0);
/* osztott
memória törlése*/
printf("torolve\n");
}
void changemode(int shmid, char
*mode)
{
struct shmid_ds myshmds;
shmctl(shmid, IPC_STAT,
&myshmds);
/* aktuális
jogok lekérdezése*/
printf("a regi jogok: %o\n", myshmds.shm_perm.mode);
sscanf(mode, "%o", &myshmds.shm_perm.mode);
shmctl(shmid, IPC_SET,
&myshmds);
/* új
jogok beállítása*/
printf("az uj jogok: %o\n", myshmds.shm_perm.mode);
}
void
usage(void)
/* használati
útmutató */
{
printf("shmtool - osztott memoria menedzselo rendszer\n\n");
printf("HASZNALAT: shmtool (w)rite <szoveg>\n");
printf("
(r)ead\n");
printf("
(d)elete\n");
printf("
(m)ode change <oktalis_mod>\n");
exit(1);
}
A fenti példa tesztelésekor a következő eredményre jutottunk:
$ shmtool w teszt
letrehozok egy uj osztott memoriazonat
kesz...
$ shmtool r
az osztott memoriazona letezik - megnyitom
segptr: teszt
$ shmtool w szasz
letrehozok egy uj osztott memoriazonat
kesz...
$ shmtool r
az osztott memoriazona letezik - megnyitom
segptr: szasz
$ shmtool d
az osztott memoriazona letezik - megnyitom
torolve
$ shmtool m 660
letrehozok egy uj osztott memoriazonat
a regi jogok: 666
az uj jogok: 660
$
A POSIX osztott
memória lehetővé teszi a folyamatok számára a kommunikációt a memória
bizonyos részeinek a megosztásával.
A UNIX operációs rendszer újabb változatai lehetoséget adnak a fájlok memórián
keresztül történo elérésére a fájlnak a memóriába ágyazásával
(ezzel lehetoség nyílik a fájl tartalmának memóriamuveletek segítségével
történo módosítására, amely gyakran hatékonyabb a hagyományos read() illetve
write() rendszerhívásoknál.)
Létrehozás (shm_open())
Megnyitja /
létrehozza az osztott memóriát.
Szintaxis
#include <fcntl.h>
#include <sys/mman.h>
int shm_open( const char *name,
int
oflag,
mode_t
mode );
Leirás:
Az shm_open() rendszerfüggvény visszatérití a name
által jelölt memória objektumhoz társított fájl deszkriptort.
Az osztott memória egészen addig fog létezni amíg a rendszer le nem ál, vagy az
összes folyamat be nem zárja (unmap) és amíg az utolsó folyamat meg nem hívja a
törlést (shm_unlink()).
Flagek:
<fcntl.h> által definiált flagek:
O_RDONLY //Read only
O_RDWR // írásra és olvasásra
O_CREAT //
Amennyiben az osztott memória létezik és az O_EXCL nincs beállítva. nem történik
semmi. Különben
az osztott memóriát létrehozza a mode által
jelölt jogosultságokkal.
O_EXCL //
HA az O_CREAT és az O_EXCL be van állítva, az shm_open() nem fog lefutni ha az
osztott memória létezik .
O_TRUNC // ha az osztott memória objektum létezik és sikeresen
meg volt nyitva O_RDWR módban, akkor a hosszát átállítja 0-ra és a
tulajdonos változatlan marad
A jogosultság bitek beállítása a mode értéke alapján történik
<sys/stat.h> által definiált szimbolikus konstanstok
Tulajdonosra
vonatkozóan
S_IRWXU
írás, olvasás, végrehajtás
S_IRUSR
olvasás
S_IWUSR
írás
S_IXUSR
végrehajtás
Csoport:
S_IRWXG
írás, olvasás, végrehajtás
S_IRGRP
olvasás
S_IWGRP
írás
S_IXGRP
végrehajtás
Többiek:
S_IRWXO
írás, olvasás, végrehajtás
S_IROTH
olvasás
S_IWOTH
írás
S_IXOTH
végrehajtás
Példa:
int
shmfd;
shmfd
= shm_open(SHMOBJ_PATH, O_CREAT | O_EXCL | O_RDWR, S_IRWXU | S_IRWXG);
if
(shmfd < 0) {
perror("In
shm_open()");
exit(1);
}
Eredmény:
A fájl deszkriptora ha sikereses volt a
létrehozás, különben -1 és beállítja az errn-ot
Osztott memória eltávolítása
(shm_unlink());
Szintaxis:
#include <sys/mman.h>
int shm_unlink( const char *name );
Az shm_unlink() hasonlít az unlink()-hez, lekapcsolódik az osztott memória
objektumról, majd ha minden folyamat
lekapcsolódott, felszabadítja a memóriát es ezáltal az osztott memóriában
tárolt adatok elvesznek
Példa:
if
(shm_unlink(SHMOBJ_PATH) != 0) {
perror("In
shm_unlink()");
exit(1);
}
Eredmény:
0: sikeres
-1:
sikertelen és errno-t beállítja
Adatok memóriába ágyazása(mmap())
Szintaxis:
#include <sys/mman.h>
caddr_t mmap( caddr_t addr,
size_t
len,
int
prot,
int
flags,
int
fd,
off_t
offset);
Paraméterek:
Az mmap() rendszerhívás első paramétere
caddr_t típusú (az ilyen típusú változók egy tetszoleges memóriacímet kaphatnak
értékül, általában char * típussal implementálják). Az első argumentumban
azt a memóriacímet kell megadnunk, ahova be akarjuk ágyazni a kérdéses fájlt
(vagy annak egy részét). A programok hordozhatósága érdekében itt 0-t adjunk
meg, ugyanis ekkor az operációs rendszer maga választ egy szabad
memóriaterületet, ahova a fájlt beágyazza. Sikeres végrehajtás esetén az mmap()
rendszerhívás az fd argumentumban kijelölt fájldeszkriptorú fájl offset
argumentumában adott pozíciótól kezdődő len argumentumban bájtokban
megadott hosszú részét beágyazza, és a rendszerhívás visszatérési értéke a
beágyazott fájl-rész memóriabeli kezdőcíme (a beágyazás kezdőcíme).
A prot paramétert a <sys/mman.h> header
allományban tárolt szimbólikus konstansok bitenkénti VAGY muvelettel képzett
kapcsolatával állíthatjuk elő aszerint, hogy a beágyazott fájl-részen
milyen müveleteket akarunk megengedni. Ha egy fájlra nincs írási engedélyünk a
hozzá tárolt rwx-bitek alapján, akkor a memóriába ágyazással sem módosíthatjuk
azt.
<sys/mman.h> által definiált szimbólikus konstansok:
PROT_EXEC
//végrehajtható
PROT_NOCACHE //kikapcsolja a "cache" mechanizmust
PROT_NONE //elérhetetlené teszi
PROT_READ //olvasható
PROT_WRITE //írható
Flagek:
MAP_PRIVATE // fájlon végzett
módosítások időlegesek, azaz az eredeti fájlon nem jelennek meg, a fájl
többi felhasználója nem látja azokat
MAP_SHARED
MAP_FIXED //Pontosan értelmezi
az addr paramétert
Példa:
shared_msg
= (struct msg_s *)mmap(NULL, shared_seg_size, PROT_READ | PROT_WRITE,
MAP_SHARED, shmfd, 0);
if (shared_msg == NULL) {
perror("In mmap()");
exit(1);
}
Memória felszabadítása(munmap())
Szintaxis:
#include <sys/mman.h>
int munmap( void *addr, size_t len );
Eltávolítja az
addr címtől kezdve, len byteon keresztül a mmap által a memóriához való
hozzárendeléseket. Amennyiben az adott tartományban nem volt a memóriához
rendelve semmi, az munmap() nem csinál semmit.
Példa:
if
(munmap(shared_msg,shared_seg_size)==-1){
perror("munmap:");
}
Eredmény:
0: sikeres
-1:
sikertelen és errno-t beállítja
Szintatxis:
#include <sys/mman.h>
int mprotect( void *addr,
size_t
len,
int
prot );
Beállítja a memóriához való hozzáférést addr címtől
kezdődően, len byteon keresztül. Prot határozza meg a hozzáférés
módosítót(mmap() függvénynél leirt
szimbólikus konstansok).
Példa:
if (mprotect(shared_msg,shared_seg_size,
PROT_NONE)==-1){
perror("mprotect");
}
Eredmény:
0: sikeres
-1:
sikertelen és errno-t beállítja
Szintaxis:
#include <unistd.h>
#include <sys/types.h>
int ftruncate(int fd, off_t length)
fd deszkriptoru fájlt length méretre alakítja. Ha eredetileg hosszabb volt,
levágja a végét ( elvesztődik ), ha pedig rövidebb volt, kibővíti és
az új rész \0-t fogja tartalmazni.
Példa:
if (ftruncate(shmfd, shared_seg_size)==1)
{
perror("ftruncate:");
}
Eredmény:
0: sikeres
-1:
sikertelen és errno-t beállítja
Server: Létrehozza az osztott memóriát, beleír egy
msg_s típusú struktúrát ( tartalmát véletlenszerűen generálja), majd
várakozik egészen addig amíg a
kliens át nem írja a típust -1 re.
Ha a kliens átírta a típust -1 re, törli az osztott memóriát és kilép.
Client: Csatlakozik az osztott memóriára, kiolvassa
a tartalmát majd a típust átírja -1 re
server.c:
#include
<stdio.h>
#include <sys/mman.h>
#include
<sys/types.h>
#include
<unistd.h>
#include
<fcntl.h>
#include
<sys/stat.h>
#include
<stdlib.h>
#include
<time.h>
#define
SHMOBJ_PATH "/example"
#define
MAX_MSG_LENGTH 50
#define TYPES 8
/* üzenet struktúra
*/
struct msg_s {
int type;
char content[MAX_MSG_LENGTH];
};
int main(int argc,
char *argv[]) {
int shmfd;
int shared_seg_size = (sizeof(struct
msg_s)); /* megosztott
szegmens mérete (jelen esetben 1 darab struktúrát fogunk megosztani)*/
struct msg_s *shared_msg;
shmfd = shm_open(SHMOBJ_PATH, O_CREAT |
O_EXCL | O_RDWR, S_IRWXU | S_IRWXG); /* memória
objektum létrehozása */
if (shmfd < 0) {
perror("In shm_open()");
exit(1);
}
printf("Created shared memory object
%s\n", SHMOBJ_PATH);
ftruncate(shmfd, shared_seg_size); /* méret beállítása, férjen el az
egész struktúra */
/*
struktúra
megosztása */
shared_msg = (struct msg_s *)mmap(NULL,
shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
if (shared_msg == NULL) {
perror("In mmap()");
exit(1);
}
printf("Shared memory segment
allocated correctly (%d bytes).\n", shared_seg_size);
srandom(time(NULL));
shared_msg->type = random() % TYPES; /* osztott memória tartalmának
megváltoztatása */
int tmp = shared_msg->type;
snprintf(shared_msg->content,
MAX_MSG_LENGTH, "My message, type %d, num %ld", shared_msg->type,
random());
printf("waiting...\n");
/* várakozás
amíg a kliens át nem írja a típust -1 re. Az aktív várakozás nem a legjobb de
jelen esetben az egyszerűség kedvéért ez is megfelel */
while (shared_msg->type==tmp) { };
printf("type = %d\n
",shared_msg->type);
if (munmap(shared_msg,shared_seg_size)==-1){
perror("munmap:");
}
printf("Munmap:
succes\nclose\n");
if (shm_unlink(SHMOBJ_PATH) != 0) { /* lekapcsolódás az osztott memóriáról*/
perror("In shm_unlink()");
exit(1);
}
return 0;
}
client.c:
#include
<stdio.h>
#include
<unistd.h>
#include
<sys/mman.h>
#include
<sys/types.h>
#include
<fcntl.h>
#include
<sys/stat.h>
#include
<stdlib.h>
#include
<time.h>
#define
SHMOBJ_PATH
"/example"
#define
MAX_MSG_LENGTH 50
#define TYPES 8
/* üzenet struktúra
*/
struct msg_s {
int type;
char content[MAX_MSG_LENGTH];
};
int main(int argc,
char *argv[]) {
int shmfd;
int shared_seg_size = (sizeof(struct
msg_s)); /* megosztott
szegmens mérete (jelen esetben 1 darab struktúrát fogunk megosztani)*/
struct msg_s *shared_msg;
shmfd = shm_open(SHMOBJ_PATH, O_RDWR,
S_IRWXU | S_IRWXG); /* memória
objektum megnyitása*/
if (shmfd < 0) {
perror("In shm_open()");
exit(1);
}
printf("Connecting to the shared
memory object %s\n", SHMOBJ_PATH);
/*
struktúra
betöltése */
shared_msg = (struct msg_s *)mmap(NULL,
shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
if (shared_msg == NULL) {
perror("In mmap()");
exit(1);
}
printf("Message type is %d, content
is: %s\n", shared_msg->type, shared_msg->content);
shared_msg->type = -1;
return 0;
}
Makefile(Fedora disztribúció):
SRC1 = server.c
SRC2 = client.c
OBJ1 =
$(SRC1:.c=.o)
OBJ2 = $(SRC2:.c=.o)
CFLAGS = -Wall -pedantic --ansi -D_GNU_SOURCE
-std=gnu99
INCLUDES = -I./
LIBS = -lrt
LIBPATH =
DEP_FILE = .depend
SNDR = s
RCVR = kl
.PHONY: all clean
distclean
all: depend $(SNDR)
$(RCVR)
$(SNDR): $(OBJ1)
@echo Makefile - linking $@
@$(CC) $(LIBPATH) $(LIBS) $^ -o $@
$(RCVR): $(OBJ2)
@echo Makefile - linking $@
@$(CC) $(LIBPATH) $(LIBS) $^ -o $@
.c.o:
@echo Makefile - compiling $<
@$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
clean:
$(RM) $(OBJ1) $(OBJ2)
distclean: clean
$(RM) $(SNDR) $(RCVR)
$(RM) $(DEP_FILE)
depend: $(DEP_FILE)
@touch $(DEP_FILE)
$(DEP_FILE):
@echo Makefile - building dependencies in: $@
@$(CC) -E -MM $(CFLAGS) $(INCLUDES) $(SRC1)
>> $(DEP_FILE)
@$(CC) -E -MM $(CFLAGS) $(INCLUDES) $(SRC2)
>> $(DEP_FILE)
ifeq (,$(findstring
clean,$(MAKECMDGOALS)))
ifeq (,$(findstring
distclean,$(MAKECMDGOALS)))
-include $(DEP_FILE)
endif
endif
Kimenet:
Server.c:
$ ./s
Created shared memory object
/example
Shared memory segment
allocated correctly (56 bytes).
waiting...
type = -1
Munmap: succes
close
$
Client.c:
$ ./kl
Connecting to the shared memory object /example
Message type is 6, content is: My message, type 6, num 207394245
$
Copyright (C) Buzogány László, 2002