[so] Crearea si deschiderea corecta de semafoare in POSIX
Lucian Adrian Grijincu
lucian.grijincu at gmail.com
Sat Dec 8 02:17:39 EET 2007
Discutand cu o parte din colegi am inteles ca mai multi nu stiu cum
se face in mod corect in mod portabil pentru POSIX compliant systems
crearea/deschiderea de semafoare. Scriu aici si nu modific pe wiki
deoarece nu toti cei care ar putea fi interesati de detaliile astea
sunt abonati la rss-ul de Recent Changes al wikiului.
POSIX nu impune o valoare initiala pentru semafoarele create cu semget.
Cel care a creat semafoarele trebuie sa le initializeze la o valoare
data prin semctl (de ex. prin SETALL). Apare o problema de sincronizare:
In mod ideal avem ceva de genul:
Server Client
------ ------
1. create sems
2. initialize sems values
3. open sems
4. modify sems state
in anumite situatii, din cauze ca operatiile de creare&initializare
nu sunt garantate a fi atomice putem avea ceva de genul:
Server Client
------ ------
1. create sems
2. open sems
3. modify sems state
4. initialize sems values
In acest caz, clientul foloseste niste semafoare neinitializate si
comportamentul nu poate fi intotdeauna prezis.
Sunt mai multe workarround-uri pentru aceasta problema, I tackle only
two here, you're welcome to contribute:
a) sincronizare creare&initializare vs. deschidere semafor prin
obiecte de sincronizare interprocess
b) folosirea campului sem_otime
a) folosim un mutex IPC (nu conteaza care e implementarea, poate fi si
un fisier /tmp/MY_APP_SEMCREATEINIT_FILE_MUTEX pe care se face
open(2)&flock(2) sau whatever else)
cazul ideal
Server Client
------ ------
1. LOCK(sems_mutex)
2. create sems
3. initialize sems values
4. UNLOCK(sems_mutex)
5. LOCK(sems_mutex)
6. open sems
7. modify sems state
8. UNLOCK(sems_mutex)
Nu mai apar alte cazuri deoarece, daca serverul este preemptat in timp
ce creaza&initializeaza semafoarele, avand mutexul blocat, clientul nu
poate rula.
b) folosirea campului .sem_otime
Campul sem_otime din <sys/sem.h>
struct semid_ds {
struct ipc_perm sem_perm; /* Ownership and permissions
time_t sem_otime; /* Last semop time */
time_t sem_ctime; /* Last change time */
unsigned short sem_nsems; /* No. of semaphores in set */
};
este modificat cand o operatie semctl modifica starea unui semafor.
Standardul POSIX garanteaza ca pentru semafoare nemodificate,
post semget valoarea lui sem_otime este zero.
Pentru a obtine o structura de tipul semid_ds folosim semctl(IPC_STAT).
Deoarece asta e o operatie "read-only", sem_otime nu e modificata.
Pentru semafoare neinitializate avem zero in acest camp iar pentru
semafoare initializate am o valoare non-zero, valoarea momentului system
la care a fost modificat semaforul. Timpul sistem e zero in secunda 0
din 1 Ianuarie 1970. Daca cineva seteaza timpul ca fiind 1 Ianuarie 1970
sau e rulat imediat dupa Tue Jan 19 03:14:07 2038. (see
http://www.2038bug.com/ )
Pseudo-C-code:
SERVER:
create semaphore
init arg.array la un set de valori initiale
semctl(lid, 0, SETALL, arg);
CLIENT:
open semaphore
do:
struct semid_ds sds;
memset(&sds, 0, sizeof(struct semid_ds));
arg.buf = &sds;
semctl(lid, 0, IPC_STAT, arg);
if(0 != sds.sem_otime)
break;
sleep(a while);
while(i have patience);
if(0 == sds.sem_otime)
//m-am plictisit asteptand ca semaforul sa fie initializat
//voi presupune ca am fost pornit inaintea serverului asa ca
//voi intoarce un cod de erroare
return -1;
else
//semaforul e bine initializat ... do your stuff.
E poate mai urata implementarea, dar nu ai dependenta de alte obiecte.
PS: am atasat chestia asta ca fisier text pentru ca e destul de
probabil ca gmail/mailman sa imi buseasca formatarea si anumite parti
sa fie ilizibile in arhive/MUA-urile voastre (am facut labu de RC, imi
permit sa folosesc cat mai multe acronime as humanly possible).
--
Lucian
-------------- next part --------------
A non-text attachment was scrubbed...
Name: sem
Type: application/octet-stream
Size: 4243 bytes
Desc: not available
Url : http://cursuri.cs.pub.ro/pipermail/so/attachments/20071208/0229029e/sem-0001.obj
More information about the so
mailing list