Tutorial Linux - Semafoare
Tutorial Linux - Semafoare Autor Florin
Adauga comentarii
Semafoarele sunt una dintre metodele de comunicare inter-proces , un mod de a semnala unui proces producerea unui eveniment in alt proces. Pentru a putea folosi semafoare trebuie incluse headerele sys/sem.h, sys/ipc.h si sys/types.h .
Pasii care trebuie urmati pentru a defini , initializa , folosi si , in final , distruge un semafor sunt urmatorii:
1) Definim o variabila de tip intreg;
int id_semafor;
2) Luam (sau cream) semaforul;
id_semafor=semget(IPC_PRIVATE, 1, 0777);
Prototipul functiei semget este urmatorul:
int semget(key_t key,int nsems,int semflg)
- functia intoarce identificatorul pentru grupul cu nsems semafoare asociat cheii key;
- daca cheia este IPC_PRIVATE sau cheia nu este IPC_PRIVATE dar semflg are setat bitul IPC_CREAT un nou grup de semafoare este creat;
- semflg contine de asemenea drepturile de acces asociate semaforului (in exemplul anterior , 0777);
- prezenta flagurilor IPC_CREAT si IPC_EXCL in semflg in acelasi timp va duce la esuarea apelului functiei semget;
In caz de succes functia intoarce un numar pozitiv care reprezinta id-ul semaforului si in caz de eroare -1
3) Daca este nou creat , vrem sa setam valoarea initiala a semaforului (de obicei este 1 , dar i se poate da orice valoare)
- pentru asta s-ar putea sa avem nevoie sa definim o structura (semun) astfel
#if defined(__GNU_LIBRARY) && !defined(_SEM_SEMUN_UNDEFINED)
//semun e deja definit
#else
//definim semun
typedef union
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
} semun;
#endif
semun value;
value.val=1;
semctl(semidscr, 0, SETVAL, value);
Prototipul functiei semctl:
int semctl(int semid,int semnum,int cmd,union semun arg)
- functia executa operatia indicata de cmd asupra setului de semafoare indicat de semid , asupra semaforului semnum din set (primul are indicele 0) folosind arg pentru asta
- in cazul exemplului de mai sus , se seteaza valoarea din value la semaforul 0 din setul indicat de semafoul nou creat
- pentru mai multe informatii legate de parametrii functiei , man semctl
4) Vrem sa folosim semaforul ( de obicei pentru sincronizari intre procese)
- exista 2 operatii care se folosesc uzual asupra unui semafor pentru asta , si au numele consacrate:down si up (sau U si V)
- down va incerca sa scada 1 din valoarea semaforului
- up va adauga 1 la valoarea semaforului
- uzual , daca un proces incearca sa faca down pe un semafor care are valoarea 0 , se va bloca acolo pana cand alt proces va face up pe acelasi semafor
ATENTIE:
- daca se folosesc threaduri , in momentul in care unul din threaduri face down pe un semafor cu valoarea 0 , intreg procesul se va bloca , adica TOATE THREADURILE pornite de acel proces
- pentru sincronizare intre threaduri vor trebui folosite mijloace dedicate;
Functiile down si up:
void down(int semid,short flags)
{
//scade valoarea 1 dintr-un semafor
char buf[64];
struct sembuf op;
//scad valoarea 1 din semafor
op.sem_num = 0;
op.sem_op = -1;
op.sem_flg = flags;
if(semop(semid, &op, 1)==-1)
{
//eroare
strcpy(buf,"Eroare la semop!\n");
write(1,buf,strlen(buf));
exit(-1);
}
}
void up(int semid,short flags)
{
//adauga 1 la valoarea unui semafor
char buf[64];
struct sembuf op;
//adaug 1 la valoarea din semafor
op.sem_num = 0;
op.sem_op = 1;
op.sem_flg = flags;
if(semop(semid, &op, 1)==-1)
{
//eroare
strcpy(buf,"Eroare la semop!\n");
write(1,buf,strlen(buf));
exit(-1);
}
}
Prototipul functiei semop:
int semop(int semid,struct sembuf *sops,unsigned nsops)
- nsops se foloseste pentru a specifica numarul de operatii care trebuiesc efectuate (in sops va trebui sa se gaseasca un vector)
- daca flags contine IPC_NOWAIT , procesul nu se va bloca daca valoarea din semaforul asupra caruia vrea sa faca operatia si apelul va intoarce -1
- daca flags contine IPC_UNDO , toate operatiile vor fi undone cand procesul se termina;
5) Dupa ce ne jucam cu semaforul , vrem sa-l distrugem
semctl(id_semafor, 0, IPC_RMID, NULL);
- apelam functia semctl cu parametrul cmd IPC_RMID
Semafoarele sunt resurse sistem , trebuie distruse cand nu mai sunt folosite , altfel vor continua sa ocupe resursele sistemului. Pentru a vedea toate resursele IPC care sunt active la un moment dat in sistem , puteti folosi comanda ipcs din consola. Resursele(semafoare,cozi de mesaje,memoria partajata) pot fi distruse si direct din consola cu comanda ipcrm. Folositi man ipcs si man ipcrm pentru mai multe detalii.