Szemaforok
(semaphores)
Olyan jelek, amelyek megmutatják, hogy egy folyamat
végrehajthat-e egy programrészt vagy sem...
Szemafor
adatainak lekérdezése, módosítása és törlése (semctl)
Szemafor
értékének növelése és csökkentése (semop)
Üzenetsorok (message queues)
A processzor maximális kihasználása érdekében az operációs rendszerek
jelentős része – így a Unix is – engedélyezi a folyamatoknak a
párhuzamos (egyidőben történő) futást. Ez a megoldás igen hatékony,
de mi történik akkor, ha két folyamat egyidőben próbálja elérni ugyanazt
az erőforrást? Ilyen "érzékeny" erőforrások például a
nyomtató vagy a memória, amelyet egyszerre csak egy folyamat használhat,
különben a műveletnek előre nem látható következményei lehetnek.
Kritikus szakasznak nevezzünk tehát egy olyan módosítást
a rendszeren, amelyet nem szabad megszakítani. A kritikus szakasz
erőforráshoz kötött (például a nyomtatóhoz).
A szemaforok lehetővé teszik a felhasználók számára a folyamatok
szinkronizálását. Általában a szemafor egy egész változó, amelyhez
hozzárendelünk egy e0(v) kezdeti értéket, egy e(v) aktuális értéket
és egy f(v) várakozási sort.
Az alábbiakban bemutatjuk a legismertebb szinkronizációs P és V
eljárásokat.
P(v)
{
e(v) = e(v) - 1;
if (e(v) < 0)
{
folyamat_allapota = WAIT;
f(v) sorba <- folyamat;
}
}
V(v)
{
e(v) = e(v) + 1;
if (e(v) <= 0)
{
folyamat <- f(v) sorból;
kivalasztott_folyamat_allapota = READY;
}
}
A szemafor aktuális állapotát a következő képlet adja:
e(v) = e0(v) + nˇV(v) – nˇP(v)
ahol:
nˇV(v) – a v
szemaforon végrehajtott V eljárások száma,
nˇP(v) – a v szemaforon végrehajtott P
eljárások száma.
Tehát egy kritikus szakasz megvalósítása a következőképpen történik: a
szemafor kezdeti értéke 1 lesz, a kritikus szakaszt pedig a P és V eljárások
határolják körül.
P(v)
kritikus
szakasz
V(v)
folyamat
többi része
Megjegyezzük, hogy a P és V eljárás és áltatában a szinkronizáló eljárások
feloszthatatlanok (atomi műveletek).
A UNIX System V verzióban a szemafor fogalmát általánosították. Ezért egy
szemafor esetében egyidőben akár több műveletet is megadhatunk (a P és V
eljárások más-más időben hívódnak meg a folyamaton belül), és az e(v)
értékének növelése vagy csökkentése nem feltétlenül 1-el kell történjen. Minden
a rendszer által végrehajtott művelet feloszthatatlan. Tehát ha a rendszer
nem tudja elvégezni a folyamat által kért összes műveletet, nem végzi el
egyiket sem, és a folyamat várakozási állapotba kerül egészen az összes
művelet végrehajtásáig.
Egy folyamat létrehozhat egy egész szemaforköteget. A kötegnek van egy
bemenete a szemafortáblában, amely a szemaforköteg fejlécét tartalmazza. A
folyamathoz rendelt táblázat pontosan annyi elemből áll, amennyi szemafor
tartozik a köteghez. Minden elem megőrzi az illető szemaforhoz
rendelt értéket.
A szemaforok kezelése nagyon hasonlít az osztott memória és az üzenetsorok
kezeléséhez. Ezért egy folyamatnak csak akkor van joga hozzáférni egy
szemaforhoz, ha ismeri a hozzárendelt kulcsot. Belsőleg a szemaforköteget
egy egész számmal azonosítjuk, ezért a folyamat bármelyik szemaforhoz
hozzáférhet
Tehát minden szemaforkötegnek van egy azonosítója (amely egy pozitív egész
szám) és egy semid_ds típusú adatszerkezete.
struct semid_ds
{
struct ipc_perm sem_perm; /* definiálja a jogokat és a
tulajdonost */
struct sem *sem_base; /* pointer az
első szemaforra a kötegből */
int
sem_nsens;
/* a kötegben található szemaforok száma */
time_t
sem_otime; /* utolsó
semop() művelet ideje */
time_t sem_ctime;
/* utolsó struktúramódosítás ideje */
};
Egy folyamat csak akkor férhet hozzá egy szemaforköteghez ha:
- a folyamat a superuser-é,
- a felhasználó ID-je (uid) megegyezik az sem_perm.cuid-vel vagy az
sem_perm.uid-vel és az sem_perm.mode tartalmazza a kívánt jogokat,
- a felhasználó csoportazonosítója (gid) megegyezik az sem_perm.cgid vagy
sem_perm.gid értékek egyikével és az sem_perm.mode tartalmazza a kívánt
jogokat,
- a felhasználó beleesik a "többi felhsználó" kategóriába és az
sem_perm.mode tartalmazza a megfelelő jogokat.
Egy szemaforhoz rendelt adatszerkezet a következő:
struct sem
{
ushort semval; /* a szemafor értéke (semval>=0)
*/
pid_t sempid; /* utolsó, műveletet
végző folyamat ID-ja */
ushort semncnt; /* azon foly. száma, amelyek a semval
növekedését várják */
ushort semzcnt; /* azon foly. száma, amelyek a
semval=0-t várják */
};
Létrehozás (semget)
A semget rendszerfüggvény lehetővé teszi egy szemaforköteg ID-jának a
meghatározását. Ha a szemaforköteg előzőleg nem létezett, a függvény
létrehozza azt. Függetlenül attól, hogy a köteg létezett-e vagy sem a
folyamatnak ismernie kell a szemaforhoz rendelt kulcsot. A függvény alakja:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nrsem, int flg);
A függvény visszatérési értéke az újonnan létrehozott vagy egy régi
szemafor azonosítója, illetve -1 hiba esetén. A key változóban a szemaforhoz
rendelt kulcsot kell megadni, míg az flg-ben a létrehozási tevékenységet és a
hozzáférési jogokat. A kulcsot a szemafort használó összes folyamatnak ismernie
kell. Az nrsem argumentum a kötegben található szemaforok számát jelenti. Ha
egy új köteget hozunk létre meg kell adnunk a változó értékét, ha viszont egy
már létező kötegre hivatkozunk az nrsem értéke 0 lesz.
Egy új szemaforköteg 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_EXCL nincs beállítva, akkor ha már létezik egy előzőleg
létrehozott köteg a megadott kulcsra, a program nem jelez hibát, hanem
visszaadja a létező köteg ID-ját.
Példa egy szemaforköteg létrehozására:
#define KEY 2003
int semid;
semid = semget((key_t) KEY, 5, IPC_CREAT | 0666);
Ha csak a szemaforköteg azonosítójára vagyunk kíváncsiak, a semget
hívásakor adjuk meg a kulcsot, a többi paraméternek pedig 0 értéket.
semid = semget((key_t) KEY, 0, 0);
Létrehozáskor a társított adatstruktúra (sem_perm) mezői a
következő információkkal töltődnek fel:
- sem_perm.cuid, sem_perm.uid – a semget függvényt meghívó
folyamathoz hozzárendelt felhasználó ID-ja,
- sem_perm.cgid, sem_perm.uid – a semget függvényt meghívó
folyamathoz hozzárendelt felhasználócsoport ID-ja,
- sem_perm.mode – a semget függvény hívásakor megadott flg
argumentum, amely a hozzáférési jogokat tartalmazza,
- sem_nsems – a semget függvény hívásakor megadott szemaforok száma,
- sem_ctime – az aktuális időt tartalmazza,
- sem_otime – értéke 0.
Előfordulhat, hogy egy szemaforköteghez nincs hozzárendelt kulcs.
Ebben az esetben a köteg létrehozásakor a semget függvény key paramétereként az
IPC_PRIVATE szimbolikus konstanst kell megadni.
Szemafor adatainak lekérdezése,
módosítása és törlése (semctl)
A semctl függvény a szemaforkötegek szintjén az információk 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/sem.h>
int semctl(int semid, int nrsem, int cmd, union semun arg);
A függvény visszatérített értéke az összes GET parancs kimeneti értéke,
kivételt képez a GETALL parancs. Minden más esetben a függvény értéke 0.
A semid paraméter a semget függvény által meghatározott szemaforköteg
azonosítója, míg az nrsem annak a szemafornak a száma, amelyen végre szeretnénk
hajtani a cmd műveletet.
A cmd argumentum tehát a kívánt műveletet határozza meg és a
következő értékeket veheti fel:
- GETVAL – a függvény visszatéríti a semval
értékét az nrsem által meghatározott szemaforban,
- SETVAL – az nrsem által meghatározott
szemafor semval paraméterének értéke arg.val lesz,
- GETPID – a függvény visszatéríti a sempid
értékét az nrsem által meghatározott szemaforban,
- GETNCNT – a függvény visszatéríti a
semncnt értékét az nrsem által meghatározott szemaforban,
- GETZCNT – a függvény visszatéríti a
semzcnt értékét az nrsem által meghatározott szemaforban,
- GETALL – minden szemafor semval értékét
elhelyezi az arg.array tömbben,
- SETALL – minden szemafor semval értékét
feltölti az arg.array tömbben megadott értékekkel,
- IPC_STAT – a semid_ds struktúra elemeit
lementi az arg.buf tömbbe,
- IPC_SET – a sem_perm.uid, a sem_perm.gid
és a sem_perm.mode mezők értékeit frissíti az arg.buf tömbben megadott
értékekkel,
- IPC_RMID – a szemaforköteg törlése; a törlés azonnali, tehát minden
ezt a szemafor használó folyamat egy EIDRM üzenetet kap, és hibával leáll.
Az arg variáns típusú változó, amely a cmd parancs által felhasznált
argumentumokat tartalmazza:
union semun
{
int
val;
/* a SETVAL-hoz */
struct semid_ds *buf; /* az IPC_STAT-hoz és az
IPC_SET-hez */
ushort *array;
/* a GETALL-hoz és a SETALL-hoz */
}
Szemafor értékének növelése és
csökkentése (semop)
A semop függvény feladata egy szemaforköteg egy elemének növelése és
csökkentése. Szintaxisa:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf op[], size_t nrop);
A függvény visszatérési értéke 0, ha a művelet sikeres volt,
ellenkező esetben -1. A semid a semget által meghatározott szemaforköteg
azonosítója.
Az op egy mutató nrop darab sembuf típusú struktúrához, ahol:
struct sembuf
{
ushort sem_num; /* a kötegben levő szemafor sorszáma */
short sem_op; /* végrehajtani kívánt művelet */
short sem_flg; /* végrehajtási körülmények */
}
Tehát minden szemafor esetén a végrehajtani kívánt műveletet a sem_op
mező jelzi. Ha:
- sem_op < 0
a. Ha semval >= |sem_op|, akkor semval = semval - |sem_op|. Ez
biztosítja, hogy a szemafor által visszatérített érték >= 0.
b. Ha (semval < |sem_op|) & (sem_flg & IPC_NOWAIT) = true, akkor
a függvény egy hibakódot térít vissza.
c. Ha semval < |sem_op| és az IPC_NOWAIT nincs megadva, akkor a folyamat
leáll, amíg a következők közül valamely feltétel nem teljesül:
- semval >= |sem_op| (egy másik folyamat
felszabadít pár erőforrást),
- a szemafor törlődik a rendszerből; a
függvény ebben az esetben -1 értéket térít vissza és errno=ERMID,
- ha egy folyamat egy jel lekezelése után visszatér, a semncnt értéke a
szemaforban csökken, és a függvény -1-et ad vissza (errno=EINTR).
- sem_op > 0
Ekkor semval = semval + sem_op.
- sem_op = 0
a. Ha a semval = 0, akkor a függvény azonnal befejeződik.
b. Ha a semval ≠ 0 és az IPC_NOWAIT be van állítva, akkor a függvény -1-et ad vissza és az
errno=EAGAIN.
c. Ha a semval ≠ 0 és az IPC_NOWAIT nincs beállítva, akkor a folyamat leáll, ameddig a
semval 0 nem lesz, vagy a szemaforköteg megsemmisül, vagy a folyamat egy jelet
kap.
Példák(Letöltés)
A következőkben megnézzük, hogyan lehet implementálni a P és V
eljárásokat:
pv.c
static
void semcall(int semid, int op)
{
struct
sembuf pbuf;
pbuf.sem_num
= 0;
pbuf.sem_op
= op;
pbuf.sem_flg
= 0;
if (semop(semid, &pbuf, 1) < 0){
perror("In
semop()");
exit(1);
}
}
void P(int semid)
{
semcall(semid, -1);
}
void V(int semid)
{
semcall(semid, 1);
}
Azért, hogy a P
és a V eljárások működését jobban megértsük tekintsük a következő
példát.
Írjunk folyamatot, amely három gyereket hoz létre. Mindenik gyerek hozzá
szeretne férni egy közös erőforráshoz. A kritikus szakasz 10 másodpercig
tart. (A valóságban a kritikus szakasznak sokkal rövidebbnek kell lennie.) A
szemafor biztosítja minden folyamat egyéni hozzáférését a kritikus szakaszban.
A tesztprogram a következő:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include "pv.c" /* a fent definiált P és V eljárások */
#define SEMPERM 0600 /*
hozzáférési jogok */
void rut_sem(int semid);
int
initsem(key_t semkey);
void main(void)
{
key_t
semkey = 0x200; /*
kulcs */
int
semid, i;
semid
= initsem(semkey); /* szemafor létrehozása */
for (i=0; i<3; i++) /* 3 darab gyerekfolyamat létrehozása */
if (fork() ==
0)
rut_sem(semid); /* erőforrási kérelmek a gyerekfolyamatoktól */
}
void rut_sem(int semid) /* szemaforok megvalósítása
*/
{
pid_t
pid;
pid
= getpid(); /*
gyerekfolyamat PID-je */
P(semid); /* belépés a kritikus szakaszba */
printf("a
%d folyamat kritikus szakaszban van\n", pid);
sleep(random()%5); /* kritikus szakasz; várakozás */
printf("a
%d folyamat elhagyja a kritikus szakaszt\n", pid);
V(semid); /* kilépés a kritikus szakaszból */
exit(0); /* gyerekfolyamat vége */
}
int
initsem(key_t semkey)
{
int
semid; /* szemafor létrehozása */
semid
= semget(semkey, 1, SEMPERM
| IPC_CREAT);
if (semctl(semid, 0, SETVAL, 1) <
0){
perror("In
semctl()"); /*
szemaforok száma = 1 */
exit(1);
}
return semid; /* szemafor ID-jának visszatérítése */
}
Makefile(Fedora disztribúció):
shmtool: teszt.c
gcc teszt.c -o teszt
A következő
tesztesetek is bizonyítják, hogy egy bizonyos időpillanatban csak egyetlen
folyamat lehet a kritikus szakaszban.
$ a.out
a 790 folyamat kritikus szakaszban van
a 790 folyamat elhagyja a kritikus szakaszt
a 791 folyamat kritikus szakaszban van
a 791 folyamat elhagyja a kritikus szakaszt
a 792 folyamat kritikus szakaszban van
a 792 folyamat elhagyja a kritikus szakaszt
A posixos szemafor tipusa sem_t . A következőképpen jelentjük be a sem_name nevű szemafort:
#include <semaphore.h>
sem_t sem_name;
Szemafor értékének inicializálása (sem_init)
#include
<semaphore.h>
int sem_init(
sem_t *sem, int pshared, unsigned value );
Argumentumok:
ˇ
sem: Szemaforra mutató pointer
ˇ pshared: flag, ami mutatja, hogy fork
esetén megosztjuk-e a szemafort vagy nem. A Linux szálak egyelőre nem
tudják kezelni
ˇ value: erre az értékre szeretnénk
beállítani
Példa sem_init –re:
sem_init(&sem_name,
0, 10); //sem_name szemafort beállítja 10-re
Várakozás szemaforra (sem_wait)
A sem_wait függvény segítségével várakozhatunk egy szemaforra.
Működése:
Ha a szemafor értéke
negatív, akkor blokkolja a hívó folyamatot, ellenkező esetben csökkenti a
szemafor értékét.
Szintaxis:
int
sem_wait(sem_t *sem);
Példa:
sem_wait(&sem_name);
//amennyiben a sem_name szemafor értéke pozitív, akkor csökkenti
// különben blokkolja a hívó folyamatot.
Szemafor értékének növelése
(sem_post)
Működése:
Növeli a szemafor értékét (eggyel).
Amennyiben van a
szemaforon blokált várakozó folyamat, akkor ezek közül egy aktiválva lesz.
Ha több folyamat is
várakozik a szemaforra, akkor az lesz értesítve, amelyiknek a prioritása a
legnagyobb a rendszerben.
Szintaxis:
#include
<semaphore.h>
int sem_post( sem_t *sem );
Például:
sem_post(&sem_name);
//növeli a sem_name szemafor értékét 1-el,
Szemafor értékének csökkentése
blokkolás nélkül (sem_trywait)
Vár egy szemaforra de nem blokkolja.
Ha a szemafor érteke
pozitív akkor csökkenti, különben egyszerűen visszatér (return). Ezzel pl.
megvizsgálhatjuk, hogy blokálódott-e volna a folyamat a szemafor értékét
csökkentő művelet során.
Szintaxis:
#include <semaphore.h>
int sem_trywait( sem_t *sem );
Például:
sem_trywait(&sem_name);
Szemafor értékének lekérdezése
(sem_getvalue)
Lekérdezi a szemafor értékét.
Szintaxis:
int
sem_getvalue(sem_t *sem, int *valp);
Paraméterezés:
sem mutató által mutatott szemafor értékét
lekéri a valp mutató által mutatott int típusú vátozóba.
Példa:
int value;
sem_t sem_name;
sem_getvalue(&sem_name, &value);
printf("A szemafor erteke %d\n", value);
Szemafor törlése (sem_destroy)
A sem_destroy() törli a szemafort. Ajánlatos csak akkor törölni, ha már egyetlen folyamat sem használja az illető szemafort.
Szintaxis:
int
sem_destroy(sem_t *sem); //kitörli a sem mutató által mutatott szemafort
Példa:
sem_destroy(&sem_name)
A szemaforok használatának klasszikus példája a termelők-fogyasztók
problémája,
ami a következőképpen implementálható POSIX szemaforok segítségével: (Letöltés)
header.h
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/mman.h>
#define
BUFFER_SIZE 5
#define
SHMOBJ_PATH "/tmp"
typedef
struct
{
int buffer[BUFFER_SIZE]; //futoszalag
sem_t ures; //üres helyek számát jelző
szemafor. kezdetben:
BUFFER_SIZE
sem_t tele; //tele helyek számát jelző
szemafor. kezdetben:
0.
sem_t pmut; //termelők mutex-e. Biztosítja, hogy egyszerre
csak egy folyamat termeljen.
sem_t cmut; //fogyasztók mutex-e. Biztosítja, hogy egyszerre
csak egy folyamat fogyasszon.
int nextin; //következő termelt adat helye
int nextout; //következő
elfogyasztani kívánt adat pozíciója
} osztottMemoriaTipus;
int
lekerOsztottMemoriaID()
{
int shmfd
= shm_open(SHMOBJ_PATH, O_RDWR, S_IRWXU | S_IRWXG);
//ha már
van ilyen key kulcsú osztott memóriaterület létrehozva
if (shmfd == -1){
shmfd = shm_open(SHMOBJ_PATH,
O_CREAT | O_EXCL | O_RDWR, S_IRWXU | S_IRWXG);
if
(shmfd < 0) {
perror("In shm_open()");
exit(1);
}
/*
adjusting mapped file size (make room for the whole
segment to map) -- ftruncate()
*/
ftruncate(shmfd,
sizeof(osztottMemoriaTipus));
}
return shmfd;
}
void
initSzemaforok(osztottMemoriaTipus*
p)
{
if(sem_init(&(p->ures),1,BUFFER_SIZE) < 0 ){
perror("In sem_init()");
exit(1);
}
if(sem_init(&(p->tele),1,0) < 0){
perror("In sem_init()");
exit(1);
}
if(sem_init(&(p->pmut),1,1) < 0){
perror("In sem_init()");
exit(1);
}
if(sem_init(&(p->cmut),1,1) < 0){
perror("In sem_init()");
exit(1);
}
p->nextin = p->nextout = 0;
}
termelo.c
#include "header.h"
void
initOsztottMemoria(osztottMemoriaTipus*
p)
{
//lenullázzuk a puffert (leürítjük a futószalagot)
int i =
0;
for(i=0; i<
BUFFER_SIZE; ++i){
p->buffer[i] = 0;
}
}
void
termel(osztottMemoriaTipus*
p)
{
//a
termelo elkezdi pakolni a termekeket a futoszalagra
int item = -1;
sem_wait(&(p->ures));
sem_wait(&(p->pmut));
item = rand()%10 + 1;
printf("%d\n",item);
p->buffer[p->nextin] = item;
p->nextin++;
p->nextin %= BUFFER_SIZE;
sem_post(&(p->pmut));
sem_post(&(p->tele));
}
int
main()
{
int shmfd
= lekerOsztottMemoriaID();
int t;
srand(getpid());
osztottMemoriaTipus * p;
int shared_seg_size
= sizeof(osztottMemoriaTipus);
/*
requesting the shared segment -- mmap() */
p = (osztottMemoriaTipus *)mmap(NULL, shared_seg_size,
PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
if (p == NULL) {
perror("In mmap()");
exit(1);
}
initOsztottMemoria(p);
initSzemaforok(p);
for(t=0; t<20; t++){
termel(p);
}
return 0;
}
fogyaszto.c
#include "header.h"
void
fogyaszt(osztottMemoriaTipus*
p)
{
//a
fogyaszto elkezdi levenni a termekeket a futoszalagrol
int item;
sem_wait(&(p->tele));
sem_wait(&(p->cmut));
item = p->buffer[p->nextout];
printf("%d\n",item);
p->nextout++;
p->nextout %= BUFFER_SIZE;
sem_post(&(p->cmut));
sem_post(&(p->ures));
}
int
main()
{
int shmfd
= lekerOsztottMemoriaID();
int t = 0;
osztottMemoriaTipus * p;
int shared_seg_size
= sizeof(osztottMemoriaTipus);
/*
requesting the shared segment -- mmap() */
p = (osztottMemoriaTipus *)mmap(NULL, shared_seg_size,
PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
if (p == NULL) {
perror("In mmap()");
exit(1);
}
for(t=0;t<20;++t){
fogyaszt(p);
}
if (shm_unlink(SHMOBJ_PATH)
!= 0){
perror("In shm_unlink(SHMOBJ_PATH)");
exit(1);
}
return 0;
}
Makefile(Fedora disztribúció):
all: termelo
fogyaszto
termelo: termelo.c
gcc termelo.c –pthread -lrt -o
t
fogyaszto: fogyaszto.c
gcc fogyaszto.c –pthread -lrt
-o f
clean: rm f t
.PHONY: all clean
A szemaforok használatának klasszikus példája a termelők-fogyasztók
problémája,
ami a következőképpen implementálható névvel
ellátott POSIX szemaforok segítségével: (Letöltés)
szemaforNevvel.cpp
/*
Szemaforok
és osztott memória -Nevvel ellatott szemafor
A termelő/fogyasztó problémája:
A termelő
fogyasztási cikkeket termel, melyeket elhelyez egy futószalagon
(véges puffer). A fogyasztó sorban leveszi a szalagról
a termékeket és elfogyasztja őket.
Forditani:
gcc szemaforNevvel.cpp -pthread
-lrt
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <semaphore.h>
#define
SHMOBJ_PATH "/tmp"
struct
msg_s {
int t[10];
char name_gyVf[10];
char name_termekek[10];
char name_tele[10];
};
int
main(int argc, char *argv[]) {
sem_t * sem_gyVf;
//gyarthatunk-e v fogyaszthatunk-e
sem_t * sem_termekek;
//varakozo termekek
sem_t * sem_tele;
//tele van-e
srandom(getpid());
int myIndex;
myIndex = 2; //2 ha fogyaszto
struct msg_s
*shared_msg; /* the shared segment, and head of the
messages list */
int shmfd;
int shared_seg_size = sizeof(struct msg_s);
shmfd = shm_open(SHMOBJ_PATH,
O_RDWR, S_IRWXU | S_IRWXG);
if (shmfd < 0) {
myIndex = 1; //1 ha termelo
/* creating
the shared memory object -- shm_open() */
shmfd = shm_open(SHMOBJ_PATH,
O_CREAT | O_EXCL | O_RDWR, S_IRWXU | S_IRWXG);
if
(shmfd < 0) {
perror("In shm_open()");
exit(1);
}
/*
adjusting mapped file size (make room for the whole
segment to map) -- ftruncate()
*/
ftruncate(shmfd, shared_seg_size);
}
/*
requesting the shared segment -- mmap() */
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);
}
if(myIndex == 1){
//termelo
printf("Termelo
elindult.\n");
//meghatarozza a szemaforok nevet
strcpy(shared_msg->name_gyVf, "gyVf");
strcpy(shared_msg->name_termekek, "termekek");
strcpy(shared_msg->name_tele, "tele");
//letrehozza a szemaforokat a megadott nevvel
sem_gyVf = sem_open(shared_msg->name_gyVf,
O_CREAT, S_IRUSR | S_IWUSR, 1);
if(sem_gyVf == SEM_FAILED){
perror("In sem_open(sem_gyVf)");
exit(1);
}
sem_termekek = sem_open(shared_msg->name_termekek,
O_CREAT, S_IRUSR | S_IWUSR, 0);
if(sem_termekek == SEM_FAILED){
perror("In sem_open(sem_termekek)");
exit(1);
}
sem_tele = sem_open(shared_msg->name_tele,
O_CREAT, S_IRUSR | S_IWUSR, 3);
if(sem_tele == SEM_FAILED){
perror("In sem_open(sem_tele)");
exit(1);
}
//"uriti a futoszalagot"
for(int i=0;
i < 4; i++){
shared_msg->t[i] = 0;
}
//felrakja a termekeket a "futoszalagra"
int x;
for(int i=0;
i < 10; i++){
sem_wait(sem_tele);
sem_wait(sem_gyVf);
sem_getvalue(sem_termekek,
&x);
shared_msg->t[x] = i;
printf("%d. termek legyartva!\n", i);
sem_post(sem_termekek);
sem_post(sem_gyVf);
//alszik randomra, hogy valtozatosabb legyen a megoldas
double t = random() % 30 / 10;
sleep(t);
}
}
else{
//fogyaszto
printf("Fogyaszto
elindult.\n");
//megnyitja a szemaforokat
sem_gyVf = sem_open(shared_msg->name_gyVf, 0);
if(sem_gyVf == SEM_FAILED){
perror("In sem_open(sem_gyVf)");
exit(1);
}
sem_termekek = sem_open(shared_msg->name_termekek, 0);
if(sem_termekek == SEM_FAILED){
perror("In sem_open(sem_termekek)");
exit(1);
}
sem_tele = sem_open(shared_msg->name_tele, 0);
if(sem_tele == SEM_FAILED){
perror("In sem_open(sem_tele)");
exit(1);
}
//leszedi a termekeket
int x;
for(int i=0;
i < 10; i++){
sem_wait(sem_termekek);
sem_wait(sem_gyVf);
printf("%d. termek elfogyasztva!\n", shared_msg->t[0]);
for(int j = 0; j < 3; j++)
shared_msg->t[j] = shared_msg->t[j+1];
sem_post(sem_tele);
sem_post(sem_gyVf);
//alszik o is randomra, hogy minden
futtatasnal kicsit maskepp mukodjon
double t = random() % 30 / 10;
sleep(t);
}
}
if(myIndex == 2)
{
//a
fogyaszto zarja be a szemaforokat
if (sem_unlink(shared_msg->name_gyVf) != 0)
{
perror("In sem_unlink(shared_msg->sem_gyVf)");
exit(1);
}
if (sem_unlink(shared_msg->name_termekek) != 0)
{
perror("In sem_unlink(shared_msg->sem_termekek)");
exit(1);
}
if (sem_unlink(shared_msg->name_tele) != 0)
{
perror("In sem_unlink(shared_msg->sem_tele)");
exit(1);
}
//es torli az osztott memoriat
if
(shm_unlink(SHMOBJ_PATH) != 0)
{
perror("In shm_unlink(SHMOBJ_PATH)");
exit(1);
}
}
return 0;
}
Makefile(Fedora disztribúció):
termelo:
szemaforNevvel.cpp
gcc szemaforNevvel.cpp -pthread -lrt -o sz
Osztott memória (shared memory)
Copyright (C) Buzogány
László, 2002
About