Programação de Sistemas Jantar dos filósofos Programação de Sistemas Jantar dos filósofos : 1/14 Introdução (1) O jantar dos filósofos, proposto por Dijkstra em 1971, é o problema mais famoso de acesso a recursos partilhados por processos concorrentes. Cinco filósofos estão sentados numa mesa redonda, alternam entre pensar e comer. O alimento consumido é esparguete, disponibilizado em quantidades ilimitadas. Para comer esparguete necessitam de dois garfos, colocados ao seu lado. Impasse ocorre se todos os filósofos pegarem o garfo do mesmo lado (ex: direito), ficando à espera que o seu colega do outro lado liberte o garfo. Figura 2-31, Modern Operating Systems Programação de Sistemas Jantar dos filósofos : 2/14
Introdução (2) Os filósofos e os garfos são numerados 0..N-1 (N é o número de filósofos). O programa recebe o tempo de simulação na linha de comando. Tempos de espera usam função sleep(unsigned sec); /* refeição demora entre 2+0 e 2+2 segundos */ #define eat(i) {printf("phil %d eating\n",i);sleep(2+(int)(random())%3; #define think(i) {printf("phil %d thinking\n",i); sleep(6+(int)(random())%6; Programação de Sistemas Jantar dos filósofos : 3/14 Introdução (3) Exploradas duas estratégias de sincronização dos recursos escassos (garfos) 1. Estado de cada filósofo conhecido por todos Semáforo door assegura exclusão mútua. Caso pelo menos um dos vizinhos esteja a comer, o filósofo fica bloqueado na tabela de semáforos s (é libertado pelo filósofo vizinho, quando retorna garfo). 2. Garfos geridos por gestor, através de mensagens enviadas por pipes. A solução por gestor é mais pesada (mais processos e custo de distribuição de mensagens), mas conceptualmente mais simples de implementar. Programação de Sistemas Jantar dos filósofos : 4/14
Resolução por semáforos (1) Os estados de cada filósofo indicados numa tabela typedef enum {thinking, hungry, eating Tstate; Tstate state[n]; Os vizinhos do filósofo i são Esquerdo: (i-1)%n Direito: (i+1)%n O fio de execução do filósofo possui como parâmetro a sua posição. Ao todo existem 6 semáforos Acesso à região crítica: sem_t door; Espera que vizinho liberte garfo: sem_t s[n]; Programação de Sistemas Jantar dos filósofos : 5/14 Resolução por semáforos (2) #include <pthread.h> #include <semaphore.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #define N 5 // philosophers #define left(i) ( (i-1)%n ) #define right(i) ( (i+1)%n ) #define eat(i) {printf("phil %d eating\n",i); sleep(2+2*random()/rand_max); #define think(i) {printf("phil %d thinking\n",i);sleep(6+3*random()/rand_max); typedef struct { int pos; arguments; typedef enum {thinking, hungry, eating Tstate; Tstate state[n]; sem_t door; /* acesso à regiao crítica */ sem_t s[n]; /* espera de cada filósofo */ Programação de Sistemas Jantar dos filósofos : 6/14
Resolução por semáforos (3) void take_forks(int i) { sem_wait(&door); state[i] = hungry; test(i); sem_post(&door); sem_wait(&s[i]); /* bloqueia se grafos não foram adquiridos */ void put_forks(int i) { sem_wait(&door); state[i] = thinking; test(left(i)); test(right(i)); sem_post(&door); Programação de Sistemas Jantar dos filósofos : 7/14 Resolução por semáforos (4) void test(int i) { if ( state[i] == hungry ) { if( state[left(i)]!= eating && state[right(i)]!= eating ){ state[i] = eating; sem_post(&s[i]); else printf("phil %d hungry\n", i); void *philosopher(void *arg) { arguments *argument=(arguments *)arg; int i; i = argument->pos; while(1) { think(i) take_forks(i); eat(i) put_forks(i); Programação de Sistemas Jantar dos filósofos : 8/14
Resolução por semáforos (5) int main(int argc, char *argv[]) { int i; pthread_t t[n]; arguments *arg; if(argc!=2) { fprintf( stderr, %s time\n,argv[0] ); exit(1); /* inicializa semáforos */ for(i=0; i<n;i++) sem_init( &s[i],0,0 ); sem_init( &door,0,1 ); for(i=0;i<n;i++) state[i]=thinking; for(i=0;i<n;i++) { arg = (arguments *)malloc(sizeof(arguments)); arg->pos=i; t[i]=pthread_create(&(t[i]),null,philosopher,(void *)arg); if(t[i]!=0) { fprintf( stderr,"erro na criacao do thread\n ); exit(1); sleep( atoi(argv[1]) ); return 0; [rgc@asterix JantarFilosofos]$ JF1 17 Phil 0 thinking Phil 1 thinking Phil 2 thinking Phil 3 thinking Phil 4 thinking Phil 0 eating Phil 1 hungry Phil 2 eating Phil 3 hungry Phil 4 hungry Phil 1 hungry Phil 0 thinking Phil 2 thinking Phil 1 eating Phil 3 eating Phil 1 thinking Phil 3 thinking Phil 4 eating Phil 4 thinking Phil 0 eating Phil 2 eating Phil 0 thinking Phil 2 thinking Phil 1 eating Phil 3 eating [rgc@asterix JantarFilosofos]$ Programação de Sistemas Jantar dos filósofos : 9/14 Resolução por mensagens (1) Garfos vizinhos do filósofo i são i e (i+1)%n O simulador possui os seguintes canais de comunicação Um pipe de envio de pedidos para o gestor Cada processo possui um pipe, por onde o gestor envia a resposta ao pedido. O pedido do filósofo é uma cadeia de 3 caracteres: 1. Número de filósofo ( 0 +i) 2. Requerimento ('P' para pedir garfos, 'L' para libertar garfos) 3. Canal de escrita da resposta para o filósofo ( A +canal) Constantes /* Códigos de acção */ #define GRAB 'P' #define RELEASE 'L' /* Códigos de resposta do gestor ao pedido de um filósofo */ #define DENY '0' #define OK '1' Programação de Sistemas Jantar dos filósofos : 10/14
Resolução por mensagens (2) Pipes usados para comunicação int fd[n][2]; /* gestor->filosofo (resultado) */ int request[2]; /* filosofo->gestor (pedido/libertação garfo) */ Cada um dos 5 filósofos é um processo void phil( int p_numb, /* numero de filosofo 0-4 */ int quest, /* canal escrita fil->gestor */ int w_mng, /* canal escrita gestor->fil */ int r_mng /* canal leitura gestor->fil */ ); O gestor recebe como parâmetro o canal de leitura dos pedidos void manager( int in ); /*descritor do canal de leitura dos pedidos*/ Programação de Sistemas Jantar dos filósofos : 11/14 Resolução por mensagens (3) void phil( int p_numb, int quest, int w_mng, int r_mng) { for(;;) { phil_status my_status = thinking; depict_status(p_numb,my_status); sleep( 8+(int)(random())%5 ); for(;;) { /* pede garfos */ msg[0]=grab; msg[1]='0'+p_numb; msg[2]='a'+w_mng; msg[3]='\0'; write(quest,msg,len); read(r_mng,msg,len); /* espera resposta */ if(msg[0]==deny) { my_status = waiting; depict_status(p_numb,my_status); sleep(6+(int)(random())%3; else { my_status = eating; depict_status(p_numb,my_status); sleep( 3+(int)(random())%3 ); /* liberta garfos */ msg[0]=release; msg[1]='0'+p_numb; msg[2]='a'+w_mng; msg[3]='\0'; write( quest,msg,len ); break; Programação de Sistemas Jantar dos filósofos : 12/14
Resolução por mensagens (4) void manager(int in) { int idx; int left,right; /* inicializa estado dos garfos */ for( idx=0;idx<n;idx++ ) busy[idx] = FALSE; for(;;) { read( in,msg,len ); left = msg[1]-'0'; right = (msg[1]-'0'+1)%n; if ( msg[0]==grab ) { if( busy[left]==false && busy[right]==false ) { busy[left] = busy[right] = TRUE; msg[0] = OK; else msg[0] = DENY; write( msg[2]-'a',msg,len ); else busy[left] = busy[right] = FALSE; Programação de Sistemas Jantar dos filósofos : 13/14 Resolução por mensagens (5) int main(int argc, char *argv[]) { int idx; pid_t res, f[n]; if( argc!=2 ) { fprintf( stderr, %s time\n,arv[0] ); exit(1); /* cria pipes para os filósofos */ for(idx=0; idx<phil_numb; idx++) pipe(fd[idx]); pipe(request); /* cria pipe para gestor de garfos */ /* lança os filósofos */ for( idx=0;idx<phil_numb;idx++ ) { res = fork(); if( res==0 ) phil(idx, request[1], fd[idx][1], fd[idx][0]); else f[idx] = res; res=fork(); /* lança gestor */ if( res==0 ) manager(request[0]); [rgc@asterix JantarFilosofos]$ JF2 17 Phil number 0 is Thinking Phil number 1 is Thinking Phil number 2 is Thinking Phil number 3 is Thinking Phil number 4 is Thinking Phil number 0 is Eating Phil number 1 is Waiting Phil number 2 is Eating Phil number 3 is Waiting Phil number 4 is Waiting Phil number 0 is Thinking Phil number 2 is Thinking Phil number 1 is Eating Phil number 3 is Eating Phil number 4 is Waiting Phil number 1 is Thinking Phil number 3 is Thinking sleep(atoi(argv[1])); /* adormece tempo de simulação */ /* elimina processos antes de fechar programa */ for( idx=0;idx<phil_numb;idx++ ) kill(f[idx],sigkill); kill( res,sigkill ); return 0; Programação de Sistemas Jantar dos filósofos : 14/14