eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\n_prev.gif  eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\n_up.gif  eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\n_next.gif  eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\n_home.gif

Szemaforok (semaphores)

Olyan jelek, amelyek megmutatják, hogy egy folyamat végrehajthat-e egy programrészt vagy sem...


 

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\n_link.gif  Definíció

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\n_link.gif  Műveletek szemaforokkal

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\g_link.gif  Létrehozás (semget)

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\g_link.gif  Szemafor adatainak lekérdezése, módosítása és törlése (semctl)

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\g_link.gif  Szemafor értékének növelése és csökkentése (semop)

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\n_link.gif  Példák

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\n_link.gif  POSIX kiegészítés

 

 


 

 

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\n_link_p.gif  Üzenetsorok (message queues)

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\n_book.gif  Definíció

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 */
};

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\n_book.gif  Műveletek szemaforokkal

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\g_book.gif  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.

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\g_book.gif  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 */
}

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\g_book.gif  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.

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\n_book.gif  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

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\n_book.gif  POSIX kiegészítés

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;

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\g_book.gif  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

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\g_book.gif  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.

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\g_book.gif  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,

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\g_book.gif  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);

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\g_book.gif  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);

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\g_book.gif  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



eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\buttons\n_link_n.gif  Osztott memória (shared memory)

 

 


 

Copyright (C) Buzogány László, 2002

eírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: Leírás: D:\!SO2\html\art\simple.gif

About