[Sistemi Operativi] Sincronizzazione dei processi

MisterItaly
Ciao a tutti!

Sto facendo degli esercizi sulla sincronizzazione dei processi ma ho alcuni dubbi (chiedo scusa in anticipo se dovessero essere domande un po' banali, ma sono davvero nel pallone).

Vi scrivo la traccia del primo esercizio: "Un sistema è costituito da un processo controllore (S), tre processi produttori di caratteri (A, B e C) ed N processi client che devono leggere i tre caratteri, una sola volta, prima di terminare l'esecuzione. S decide in maniera casuale quale dei tre processi produttori deve produrre il prossimo carattere e scrive la scelta in un'area di memoria X. I tre processi produttori accedono ad X per scoprire chi dovrà produrre il prossimo carattere e quello prescelto inserisce il carattere in un'area di memoria Y. I client accedono ad Y in maniera esclusiva. Un client che non ha precedentemente letto il carattere contenuto in Y lo preleva, altrimenti libera la risorsa e torna in attesa di un nuovo carattere."

Questo è il mio svolgimento (va scritto in pseudocodice):

AREA DATI:

N // #numero processi client

mutex produttore [3] = 0  // array di semafori binari per risvegliare i produttori

struct client
{
	boolean previous_char [3] = false;
	int contatore = 0;
};

typedef struct client CLIENTE;

CLIENTE [N]; // array di struct CLIENTE relativo ai client;

CODICE:

CONTROLLORE_S ()
{
	while (true)
	{
		wait (mutex_1);
		X = rand() %3 +1; // scelgo a caso il produttore
		signal (mutex_1);
		signal (produttore[X]); // risveglio il produttore X
	}
}

PRODUTTORE ()
{
	wait (produttore[X]); // aspetto la scelta del produttore
	
	wait (mutex_2)
	genera_char(Y); // genero un carattere e lo memorizzo in Y
	signal (carattere_generato);
	signal (mutex_2);
	
}

CLIENT ()
{
	while (CLIENTE[i].contatore < 3)
	{
		wait (carattere_generato);
		wait (mutex_3);
		if ((Y == 'A') && (CLIENTE[i].previous_char[1] == false)) // il carattere generato è A e 	

						il client non l'ha letto prima
		{
			read_char_y();
			CLIENTE[i].previous_char[1] = true;
		}
		else if ((Y == 'B') && (CLIENTE[i].previous_char[2] == false)) // il carattere generato è 

							B e il client non l'ha letto prima
		{
			read_char_y();
			CLIENTE[i].previous_char[2] = true;
		}
		else (Y == 'C') && (CLIENTE[i].previous_char[3] == false)) // il carattere generato è 		

C e il client non l'ha letto prima
		{
			read_char_y();
			CLIENTE[i].previous_char[3] = true;
		}
		signal (mutex_3);
	}
}


Il mio dubbio è questo: mettiamo caso che il controllore S generi il numero 1 e che voglia notificare al produttore 1 che deve produrre il carattere. Mettiamo sempre caso che, al momento della signal, il produttore 1 è nella sua sezione critica. A rigor di logica, la signal del controllore S andrebbe "persa" visto che non c'è nessun processo bloccato su quel semaforo, giusto? Stesso discorso per la comunicazione produttore-client. Premetto che è un caso molto limite e, ripeto, non so se è un ragionamento corretto: immaginiamo ci sia un client in sezione critica e che tutti gli altri client siano in attesa sul mutex_3; nel frattempo, uno dei produttori genera un carattere e fa una signal per notificare la cosa ad uno dei client. Anche qui, la signal del produttore andrebbe persa perchè non c'è nessun client in attesa su carattere_generato, giusto?

Se tutto questo è giusto, sarebbe preferibile ragionare così? Vanno creati altri semafori di controllo, opportunamente inizializzati ed inseriti nel codice, per aspettare che il produttore scelto sia disponibile per l'ascolto (così da non "sprecare" nessuna signal) e per aspettare che almeno un client sia in ascolto? Diciamo una cosa del genere:

AREA DATI:

N // #numero processi client

mutex produttore [3] = 1 // array di semafori binari per verificare se il produttore scelto è libero
mutex carattere_generato [3] = 0  // array di semafori binari per risvegliare il produttore selezionato

struct client
{
	boolean previous_char [3] = false;
	int contatore = 0;
        mutex client_libero = 1; // semaforo binario per indicare se il client è libero o no
};

typedef struct client CLIENTE;

CLIENTE [N]; // array di struct CLIENTE relativo ai client;



CONTROLLORE_S ()
{
	while (true)
	{
		wait (mutex_1);
		X = rand() %3 +1; // scelgo a caso il produttore
                signal (mutex_1);
		wait (produttore[X]); // aspetto che il produttore X sia libero
		signal (carattere_generato[X]); // risveglio il produttore X
	}
}

PRODUTTORE ()
{
	wait (carattere_generato[X]); // aspetto che ci sia il carattere
	
	wait (mutex_2)
	genera_char(Y); // genero un carattere e lo memorizzo in Y
	wait (CLIENTE.client_libero[i]); //aspetto che ci sia almeno un client in attesa
	signal (carattere_generato);
	signal (mutex_2);
	signal (produttore[X]); // il produttore X è libero
	
}

CLIENT ()
{
	while (CLIENTE[i].contatore < 3)
	{
		wait (carattere_generato);
		wait (mutex_3);
		if ((Y == 'A') && (CLIENTE[i].previous_char[1] == false)) // il carattere generato è A e 	

						il client non l'ha letto prima
		{
			read_char_y();
			CLIENTE[i].previous_char[1] = true;
		}
		else if ((Y == 'B') && (CLIENTE[i].previous_char[2] == false)) // il carattere generato è 

							B e il client non l'ha letto prima
		{
			read_char_y();
			CLIENTE[i].previous_char[2] = true;
		}
		else (Y == 'C') && (CLIENTE[i].previous_char[3] == false)) // il carattere generato è 		

C e il client non l'ha letto prima
		{
			read_char_y();
			CLIENTE[i].previous_char[3] = true;
		}
		signal (mutex_3);
		signal (CLIENTE.client_libero[i]); // il client i-simo è libero
	}
}


Che ne dite?

Grazie in anticipo per le risposte! :wink:

Risposte
hamming_burst
Ciao,
ma sono due esercizi, oppure lo stesso esercizio risolto con due metodi differenti e chiedi quale sia quello corretto e che risolve il problema di concorrenza? (te lo chiedo perchè non ho voglia di leggermi tutto il codice per capirlo).

Se usi pseudocodice deduco tu intenda rimanere in astratto da un OS particolare. Quindi utilizzare la semantica dei thread (invece che i processi che utilizzano scambio di messaggio es. in linux) non è un problema.

MisterItaly
Ciao,

è lo stesso esercizio risolto in due modi diversi e vorrei sapere, secondo voi, qual'è il metodo più corretto. :)

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.