Home > C > Semaphores in C

Semaphores in C


Quando si parla di processi in C, è utile introdurre il concetto di SEMAPHORES. Un semaphore in informatica viene utilizzato pe gestire l’accesso ad una risorsa condivisa e viene implementato sulla base di un valore intero e di due primitive: UP e DOWN.

Posto che il valore dell’intero venga identificato con V, allora:

  • se V > 0 un’operazione di DOWN ne abbassa il valore di un’unità
  • se V = 0 un’operazione di DOWN viene messa in attesa finchè V > 0 e poi ne abbassa il valore di un’unità
  • un’operazione di UP aumenta il valore di V di un’unità

Un semaforo in C può essere creato utilizzando la seguente sintassi:

key_t key; //key
int sem_id; //semaphore id
int nsems = 10; //number of semaphores in the set

key = ftok("/home/belleforonte/aaa", 7);
sem_id = semget(key, nsems, 0666|IPC_CREAT); // last one is (access rights | create/re-use)

La variabile key rappresenta una chiave e viene creata tramite il comando ftok(const char *pathname, int proj_id); dove pathname indica il percorso di un file ESISTENTE (su una directory in cui dovete avere diritti di accesso) mentre proj_id è un intero che rappresenta un id.

Dopo aver creato la chiave, andiamo ad utilizzarla nella creazione/riutilizzo di un semaforo usando il comando

semget(key_t key, int nsems, int semflg); è da notare che un precedente semaforo avrebbe potuto essere reutilizzato tramite il comando semget(key, 0, 0) dove la key avrebbe dovuto essere stata la stessa utilizzata per la creazione.

La funzione vista in precedenza ritorna -1 se non può essere eseguita correttamente, dunque se il semaphore set non è stato creato.

Semaphore

Dopo aver creato il semaphore passiamo a capire come manipolarlo tramite le operazioni di UP e DOWN.

Per effettuare operazioni con un semaphore set facciamo qualcosa di simile:

int semop(int sem_id, struct sembuf *sops, unsigned nsops);

Dove: sem_id è il valore ottenuto dal comando semget, sops è un array di comandi sul semaphore identificati da una struttura del tipo:

struct sembuf {
  u_short sem_num; // indicates which one is the semaphore to control
  short sem_op; // indicate which one is the variable to increment/decrement
  short sem_flag;
}

mentre nsops è il numero di comandi nell’array.

Nella struttura sembuf: sem_num indica il numero del semaphore nel set, sem_op indica l’operazione da eseguire, mentre sem_flg
 dovrebbe essere posta a 0.

Il semaforo viene  comandato in base al valore di sem_op, infatti
:

  • se 
sem_op
 >
 0,
 il valore del semaphore viene aumenta di sem_op
  • se sem_op
<
0
  • o se il valore del semaphore è maggiore o uguale
 al valore assoluto di sem_op, il valore del semaphore è diminuito di sem_op e poi l’esecuzione del codice continua

    o se il valore del semaphore è minore del valore assoluto di sem_op,
 l’esecuzione è sospesa finchè un altro processo non incrementa il valore del semaphore

  • se sem_op = 0, l’esecuzione è sospesa finchè il semaforo è a valore 0

Prima di vedere un esempio concreto ricordo che è FONDAMENTALE eliminare i semaphores se non si usano più. Questa procedura viene eseguita nel seguente modo:

int semctl(sem_id, 0, IPC_RMID);

Inoltre i seguenti comandi da linea di comando possono essere utili, il primo per vedere i semafori attivi e il secondo per rimuoverne uno: sotto posto il codice per vederne il man:

bellerofonte@pegaso:~$ man ipcs
.....man di ipcs
bellerofonte@pegaso:~$ man ipcrm
.....man di ipcrm

Passiamo ora a vedere l’esempio del producer-consumer.

Cito Wikipedia:

“In informatica, il problema del produttore-consumatore (conosciuto anche con il nome di problema del buffer limitato o bounded-buffer problem) è un esempio classico di sincronizzazione tra processi. Il problema descrive due processi, uno produttore (in inglese producer) ed uno consumatore (consumer), che condividono un buffer comune, di dimensione fissata. Compito del produttore è generare dati e depositarli nel buffer in continuo. Contemporaneamente, il consumatore utilizzerà i dati prodotti, rimuovendoli di volta in volta dal buffer. Il problema è assicurare che il produttore non elabori nuovi dati se il buffer è pieno, e che il consumatore non cerchi dati se il buffer è vuoto.

La soluzione per il produttore è sospendere la propria esecuzione se il buffer è pieno; non appena il consumatore avrà prelevato un elemento dal buffer, esso “sveglierà” il produttore, che ricomincerà quindi a riempire il buffer. Allo stesso modo, il consumatore si sospenderà se il buffer è vuoto; non appena il produttore avrà scaricato dati nel buffer, risveglierà il consumatore. Questa soluzione può essere implementata tramite delle strategie di comunicazione tra processi, tipicamente con dei semafori. Una soluzione errata potrebbe dar luogo ad un deadlock, in cui entrambi i processi aspettano di essere risvegliati.”

Ecco una possibile implementazione del producer:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
  key_t key = ftok("/home/belleforonte/Desktop/a", 1);//file a must exist(can be any file)
  int sem_id = semget(key, 1, 0666 | IPC_CREAT);
  getchar();

  struct sembuf sops = {
    .sem_num = 0,
    .sem_op = 1 // increment by one
  };

  semop(sem_id, &sops, 1);
}

E del  consumer:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
  key_t key = ftok("/home/belleforonte/Desktop/a", 1);//file a must exist(can be any file)
  int sem_id = semget(key, 0, 0);

  struct sembuf sops = {
    .sem_num = 0,
    .sem_op = -1 // decrease by one
  };

  semop(sem_id, &sops, 1);
  printf("Key pressed\n");
}

Finito!🙂

Categories: C Tags: ,
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: