Esperimenti con message passing in C

From Sistemi Operativi
Revision as of 11:31, 9 December 2016 by FedericoB (talk | contribs) (Aggiunta proposta astratta del problema dei filosofi.)
Jump to navigation Jump to search

Ho messo a vostra disposizione alcuni sorgenti che implementano in C le astrazioni di message passing sincrono, asincrono e completamente asincrono come le abbiamo viste (o vedremo presto) a lezione.

Ho messo il materiale in questo file.

La directory comprende:

  • un Makefile
  • suspend.[ch] è il modulo che implementa la sospensione e riattivazione dei pthread (usando il segnale SIGUSR1).
  • msg.[ch] modulo di implementazione dei paradigmi di message passing.
  • sender.c receiver.c: esempi di processi che si scambiano un messaggio (sender manda a receiver che risponde).

IL file msg.h spiega come usare i servizi forniti da questi sorgenti.

Per iniziare occorre dare il nome al processo durante l'inizializzazione del servizio:

void async_msg_init(char *procname);
void sync_msg_init(char *procname);
void nb_msg_init(char *procname);

IL tipo di servizio (sincrono, asincrono o completamente asincrono) viene deciso al momento della inizializzazione e non puo' piu' essere cambiato.

Per spedire un messaggio basta indicare il nome del destinatario, il buffer contenente il messaggio e la lunghezza in byte del messaggio.

ssize_t msg_send(char *dest, const void *buf, size_t len);

L'interfaccia e' simile alla system call "write" ma al posto del file descriptor c'e' il nome del destinatario. E' possibile inviare messaggi vuoti (di solito servono per indicare un acknowledgement. Al momento della spedizione il processo destinatario deve esistere, altrimenti la funzione ritorna errore. In caso di successo la funzione restituisce ilnumero di byte inviati, -1 un caso di errore.

Per ricevere un messaggio si usa la funzione msg_receive:

ssize_t msg_recv(char *sender, void *buf, size_t len);

Il campo sender può essere:

  • una stringa: in questo caso viene ricevuto il primo messaggio spedito dal mittente indicato
  • NULL: viene consegnato il primo messaggio ricevuto qualsiasi ne sia stato il mittente
  • una variabile di tipo msg_procname con il primo byte zero (una stringa vuota di dimensione adeguata): viene consegnato il primo messaggio ricevuto qualsiasi ne sia stato il mittente e il nome del mittente viene salvato nella variabile sender.

aggiornamento Dec. 6 2016

E' stata aggiunta una funzione per ottenere il proprio nome.

void msg_myname(char *myname);

(il parametro deve essere di tipo msg_procname per essere certi che il nome non sia più lungo del buffer).

La costante MAXLEN indica la massima lunghezza dei messaggi che la libreria gestisce.

Il makefile ha ora un parametro opzionale per la compilazione dei test/tutorial "receiver" e "sender".

make clean; make MPTYPE=async
make clean; make MPTYPE=sync
make clean; make MPTYPE=nb

generano gli eseguibili di esempio per i vari paradigmi di message passing. Lanciando da due shell diverse (e.g. due finestre terminale) prima receiver in una e poi sender nell'altra si potranno osservare le stampe dei due programmi.

aggiornamento Dec. 9 2016

Ho aggiunto questo file che contiene gli esempi di implementazione di message passing asincrono dato quello sincrono (con server) e message passing completamente asincrono dato quello sincrono.

Dining philosophers con message passing

--FedericoB (talk) 11:31, 9 December 2016 (CET) Sto cercando di implementarlo senza un agente centrale che sincronizza ma con solo i filosofi che si scambiano messaggi. Riporto la soluzione con i soli passaggi logici.

#include <stdint.h>
#include <zconf.h>
#include <stdlib.h>
#include <pthread.h>
#include <msg.h>
#include <memory.h>

#define MPTYPE np

#define __msg_init(T, X) T ## _msg_init(X)
#define _msg_init(T, X) __msg_init(T,X)
#define msg_init(X) _msg_init(MPTYPE, X)

void *philo(void *arg) {
    //inizializza message passing 
    //utilizza il mio indice di filosofo come nome
    //fai una receive in modo che il thread che gestisce la coda dei messaggi 
    //si segni che stai aspettando messaggi dal filosofo alla tua destra e alla tua sinistra
    while (1) {
        //think
        //se mentre pensavi il filosofo alla tua destra o alla tua sinistra ti hanno chiesto le bacchette allora concedile
        //chiedi le bacchette al filosofo alla tua destra e alla tua sinistra e aspetta finché non ti rispondono tutti e due
        //eating
        //guarda se ti hanno chiesto le bacchette mentre mangiavi e concedile.
        // Se non ti hanno ancora chiesto le bacchette aspetta finché non te le chiedono.
    }
}

int main(int argc, char *argv[]) {
    uintptr_t i;
    pthread_t philo_thread[5];
    srandom(time(NULL));
    for (i = 0; i <  5; i++)
        pthread_create(&philo_thread[i], NULL, philo, (void *) i);
    for (i = 0; i < 5; i++)
        pthread_join(philo_thread[i], NULL);
}

--FedericoB (talk) 11:31, 9 December 2016 (CET) Ho il problema che dopo aver pensato un filosofo non trova mai richieste per le bacchette, quindi non le concede mai e tutti vanno in deadlock.