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 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. -- Lucian