Programação de Sistemas
Programação de Sistemas
Jantar dos filósofos : 1/14
Jantar dos filósofos
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
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.
Programação de Sistemas
Jantar dos filósofos : 3/14
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;}
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
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
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
Programação de Sistemas
Jantar dos filósofos : 5/14
– 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];
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 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 */
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 */
}
Programação de Sistemas
Jantar dos filósofos : 7/14
void put_forks(int i) {
sem_wait(&door);
state[i] = thinking;
test(left(i));
test(right(i));
sem_post(&door);
}
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); }
}
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 );
[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
Programação de Sistemas
Jantar dos filósofos : 9/14
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; } 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]$
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:
• 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'
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 */
Programação de Sistemas
Jantar dos filósofos : 11/14
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*/
);
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) {
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; } }
} }
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 );
Programação de Sistemas
Jantar dos filósofos : 13/14
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; }
}
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 */
[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 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]);
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; }
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