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