Semafori e
set di semafori
Un semaforo
contiene un valore intero e permette di eseguire atomicamente la
sinconizzazione di processi, il test e il settaggio del valore interno al
semaforo.Sul semaforo possono essere eseguite due operazioni: wait e signal.
L'operazione wait
controlla se semaforo = 1 allora decrementa il valore altrimenti blocca il 252j93c
processo chiamante finchè il semaforo verrà rilasciato; l'operazione signal
incrementa il valore di semaforo (semaforo =1) e dichiara libera la risorsa
assocaiata al semaforo.Un set di semafori è una struttura contenente più
semafori che possono essere gestiti sia singolarmente sia in gruppo.
Creare un set di semafori
- semget ( )
La semget ( ), analogamente a quanto
visto nei messaggi, consente di creare un set di semafori. Essa necessita i
seguenti parametri: ID del set di semafori, il numero dei semafori di un set,
alcuni flag che servono a gestire I permessi d'accesso sui semafori.
Esempio
// variabili che conterranno l'ID del set di semafori int sem_set_id_1; int sem_set_id_2; // creazione di un set di semafori privato (accesso consentito al solo possessore) contenente un solo semaforo sem_set_id_1 = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600); if (sem_set_id_1 == -1) // creazione di un set di semafori avente ID = 250, contenente tre semafori in cui l'accesso è privato sem_set_id_2 = semget(250, 3, IPC_CREAT | 0600); if (sem_set_id_2 == -1)
In quest'ultimo caso se esiste già un set di
semafori con ID=250 allora il set dei semafori non verrà creato e si accederà
al set di semafori esistente.
Scrivere e leggere un
semaforo - semctl ( )
La semctl ( ) permette di inizializzare i
valori dei semafori di un set.
// conterrà l'ID del set di semafori ( se vale -1 significa errore) int rc; // inizializza il primo semaforo del set con il valore 3 rc = semctl(sem_set_id_2, 0, SETVAL, 3); if (rc == -1) // inizializza il secondo semaforo del set con il valore 6 rc = semctl(sem_set_id_2, 1, SETVAL, 6); if (rc == -1)
L'ultimo parametro della semctl, che indica
quale valore memorizzare in un certo semaforo, dovrebbe essere contenuto in una
struttura union semun definita nell'esempio seguente. Comunque l'operazione
SETVAL utilizza solo la parte intera della union pertanto tratteremo questo
parametro come un intero.
// uso della union semun come parametro per la semctl union semun sem_val; // inizializza il primo semaforo del set a tre sem_val.val rc = semctl(sem_set_id_2, 2, SETVAL, sem_val); if (rc == -1)
Uso dei semafori per
mutua esclusione - semop ( )
// questa funzione sovrascrive il contenuto del file con il percorso dato void update_file(char* file_path, int number) // alla fine esegue un signal sul semaforo (valore del semaforo +1) sem_op.sem_num = 0; sem_op.sem_op = 1; // COMMENTO # 3 sem_op.sem_flg = 0; semop(sem_set_id, &sem_op, 1); COMMENTO # 1: prima di accedere al file si usa la semop ( ) sul semaforo fornendogli '-1' insem_op.sem_op; ciò significa che se il valore del semaforo è maggiore o uguale a '1' decrementa tale valore di un'unità e ritorna al chiamante. Altrimenti, se il valore è '1' o minore di '1', blocca il processo chiamante finché il valore del semaforo diverrà '1' ed a quel punto ritornerà al processo chiamante; COMMENTO # 2: la semantica dell'operazione semop ( ) ci assicura che al momento dell'uscita della funzione il valore del semaforo sarà 0. COMMENTO # 3: una volta modificato il file, si incrementa il valore del semaforo di '1' possibilmente svegliando un processo che era rimasto in attesa che lo stesso semaforo si liberasse.
Il
file "sem-mutex.c" è utile per dimostrare quanto detto sulla mutua esclusione:
il programma lancia 5 processi, ognuno dei quali esegue la funzione
"update_file" diverse volte e di seguito esce. Ogni processo stampa a
video il suo PID e modifica il file.
Uso dei semafori per
problemi produttore-consumatore - semop ( )
// contenitore per l'ID del set di semafori int sem_set_id; // valore del semaforo per la semctl ( ) union semun sem_val; // struttura per operazioni sui semafori struct sembuf sem_op; // creazione di un set di semafori contenente un solo semaforo che sarà inizializzato a 0 sem_set_id = semget(IPC_PRIVATE, 1, 0600); if (sem_set_id == -1) sem_val.val semctl(sem_set_id, 0, SETVAL, sem_val); // signal sul semaforo (valore +1) sem_op.sem_num = 0; sem_op.sem_op = 1; sem_op.sem_flg = 0; semop(sem_set_id, &sem_op, 1); in un altro processo cercheremo di consumare la risorsa protetta dal semaforo bloccando il semaforo finché il suo valore sarà >=0 sem_op.sem_num = 0; sem_op.sem_op = -1; sem_op.sem_flg = 0; semop(sem_set_id, &sem_op, 1); // il semaforo vale 0 (o un numero positivo) quindi c'è qualcosa da consumare