Você está na página 1de 15

Sistemas Operacionais

Problemas de Escalonamento

O Problema do Jantar dos Filsofos (com threads)
Em cincia da computao, o problema do jantar dos filsofos um exemplo
ilustrativo de um problema comum de programao concorrente. mais um
problema clssico de sincronizao multi-processo.
O problema pode ser resumido como cinco filsofos sentados ao redor de
uma mesa redonda, cada qual fazendo exclusivamente uma das duas coisas:
comendo ou pensando. Enquanto est comendo, um filsofo no pode
pensar, e vice-versa.
Cada filsofo possui um prato cheio de espaguete sua frente. Alm disso,
um garfo posicionado entre cada par adjacente de filsofos (portanto, cada
filsofo tem exatamente um garfo sua esquerda e exatamente um garfo
sua direita).



Como espaguete uma comida difcil para se servir e comer com um nico
garfo, assume-se que um filsofo necessita de dois garfos para poder comer.
E, alm disso, um filsofo s pode utilizar um garfo que esteja imediatamente
sua esquerda ou imediatamente sua direita.
A falta de disponibilidade de garfos uma analogia falta de recursos
compartilhados em programao de computadores (situao conhecida como
concorrncia). Travar (lock) um recurso uma tcnica comumente utilizada
para assegurar que o recurso est sendo acessado somente por um programa
ou trecho de cdigo, por vez. Quando um programa est interessado em um
recurso que j foi travado por outro, o programa espera at que ele seja
destravado. Quando existem vrios programas envolvidos no travamento de
recursos, um deadlock pode acontecer, dependendo das circunstncias.
Para exemplificar, podemos citar um programa que necessita processar dois
arquivos. Quando duas instncias desse programa travam um arquivo cada,
ambos os programas esperam o outro destravar o arquivo que falta, o que
nunca ir ocorrer.
Em geral, o problema do jantar dos filsofos um problema genrico e
abstrato que utilizado para explicar diversas situaes indesejveis que
podem ocorrer em problemas que tem como principal ideia a excluso mtua.
Por exemplo, assim como no caso acima, deadlock/livelock um conceito que
pode ser bem explicado atravs do problema dos filsofos.
Abaixo encontra-se uma possvel soluo para o problema.
A soluo apresentada livre de deadlocks e permite o mximo de
paralelismo a um nmero arbitrrio de filsofos. Ela usa um arranjo, state,
para controlar se um filsofo est comendo, pensando ou faminto (tentando
pegar garfos). Um filsofo s pode mudar para o estado 'comendo' se nenhum
dos vizinhos estiver comendo. Os vizinhos do filsofo i so definidos pelas
macros LEFT e RIGHT. Em outras palavras, se i for 2, LEFT ser 1 e RIGHT
ser 3.
O programa usa um arranjo de semforos, um por filsofo; assim, filsofos
famintos podem ser bloqueados se os garfos necessrios estiverem
ocupados.
Observe que cada thread executa o procedimento philosopher como seu
cdigo principal, mas os outros procedimentos -take_forks, put_forks e test -
so procedimentos ordinrios, e no processos separados.


Sada do Programa filsofos.c

Cdigo:

#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "fcntl.h"
#include "sys/types.h"
#include "pthread.h"
#include "semaphore.h"

#define N 5 /* nmero de filsofos*/
#define LEFT (i+N-1)%N /* nmero do vizinho esquerda de i*/
#define RIGHT (i+1)%N /* nmero do vizinho direito de i*/
#define THINKING 0 /* o filsofo est pensando*/
#define HUNGRY 1 /* o filsofo est tentando pegar
garfos*/
#define EATING 2 /* o filsofo est comendo*/
#define TRUE 1
<
int state[N]; /* arranjo para controlar o estado de
cada um*/
sem_t mutex; /* excluso mtua para as regies
crticas*/
sem_t s[N]; /* um semforo por filsofo*/

/* prottipos */
void* philosopher(void* arg);
void take_forks(int i);
void put_forks(int i);
void test(int i);
void eat(int i);
void think(int i);

int main() {
int i;

sem_init(&mutex, TRUE, 1);

for(i = 0; i < N; i++) {
sem_init(&s[i], TRUE, 1);
}

pthread_t tphil[5];

/* criando os 5 filsofo - 1 thread para cada*/
for(i = 0; i < N; i++) {
pthread_create(&tphil[i], NULL, (void *) philosopher, (void *)
&i);
}

for(i = 0; i < N; i++) {
pthread_join(tphil[i], NULL);
}

return 0;
}

void* philosopher(void * arg) { /*i: o nmero do filsofo, de 0 a N-
1*/
int i = *((int *) arg);

while(TRUE) { /* repete para sempre*/
think(i); /* o filsofo est pensando*/
take_forks(i); /* pega dois garfos ou bloqueia*/
eat(i); /* o filsofo est comendo*/
put_forks(i); /* devolve os dois garfos mesa*/
}

pthread_exit(NULL);
}

void take_forks(int i) { /*i: o nmero do filsofo, de 0 a N-
1*/
sem_wait(&mutex); /* entra na regio crtica*/
state[i] = HUNGRY; /* registra que o filsofo est faminto*/
test(i); /* tenta pegar dois garfos*/
sem_post(&mutex); /* sai da regio crtica*/
sem_wait(&s[i]); /* bloqueia se os garfos no foram
pegos*/
}

void put_forks(int i) { /*i: o nmero do filsofo, de 0 a N-
1*/
sem_wait(&mutex); /* entra na regio crtica*/
state[i] = THINKING; /* o filsofo acabou de comer*/
test(LEFT); /* v se o vizinho da esquerda pode comer
agora*/
test(RIGHT); /* v se o vizinho da direito pode comer
agora*/
sem_post(&mutex); /* sai da regio crtica*/
}

void test(int i) {
if (state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT] !=
EATING) {
state[i] = EATING;
sem_post(&s[i]);
}
}

void eat(int i) { /*i: o nmero do filsofo, de 0 a N-
1*/
printf("Filosofo %d estah comendo!\n", i);
sleep( rand()%5 );
}

void think(int i) { /*i: o nmero do filsofo, de 0 a N-
1*/
printf("Filosofo %d estah pensando!\n", i);
sleep( rand()%10 );
}

O Problema do Leitores e Escritores (com mutex e semforos)
Outro problema famoso o caso dos leitores e escritores, que modela o
acesso a uma base de dados.
Imagine, por exemplo, um sistema de reserva de linhas areas, com muitos
processos em competio, querendo ler e escrever. aceitvel que mltiplos
processos leiam a base de dados ao mesmo tempo, mas, se um processo
estiver atualizando (escrevendo) na base de dados, nenhum outro processo
pode ter acesso ao banco de dados, nem mesmo os leitores. A questo :
como programar os leitores e os escritores?
Na soluo apresentada abaixo, para obter o acesso base de dados, o
primeiro leitor faz um down no semforo db. Os leitores subsequentes
meramente incrementam um contador, rc. Conforme saem, os leitores
decrescem o contador de um e o ltimo leitor a sair faz um up no semforo,
permitindo que um eventual escritor bloqueado entre.
Tal soluo contm implicitamente uma deciso sutil que vale a pena ser
comentada. Suponha que, enquanto um leitor est usando a base de dados,
um outro leitor chegue. Como ter dois leitores ao mesmo tempo no um
problema, o segundo leitor admitido. Um terceiro leitor e outros
subsequentes podem tambm ser admitidos se chegarem.
Agora, imagine que chegue um escritor. O escritor no pode ser admitido na
base de dados, pois escritores devem ter acesso exclusivo. O escritor ento
suspenso. Leitores adicionais chegam. Enquanto houver pelo menos um leitor
ativo, leitores subsequentes sero admitidos. Como consequncia dessa
estratgia, enquanto houver um fluxo estvel de leitores chegando, todos
entraro assim que chegarem. O escritor permanecer suspenso at que
nenhum leitor esteja presente. Se um novo leitor chegar - digamos, a cada
dois segundos - e cada leitor levar cinco segundos para fazer seu trabalho, o
escritor nunca entrar.
O programa poderia ser escrito de um modo um pouco diferente: se um leitor
chegar quando um escritor estiver esperando, o leitor ser suspenso logo
depois do escritor, em vez de ser admitido de imediato. Dessa maneira, um
escritor, para terminar, precisa esperar por leitores que estavam ativos
quando ele chegou, mas no por leitores que chegaram depois dele. A
desvantagem dessa soluo que se consegue menos concorrncia e,
portanto, um desempenho menor.
A implementao da soluo descrita est exemplificada abaixo para o caso
de 3 leitores e 2 escritores.


Sada do Programa readerwriter.c

Cdigo:

#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
#include "pthread.h"
#include "semaphore.h"

#define TRUE 1

sem_t mutex; /* controla o acesso a 'rc' */
sem_t db; /* controla o acesso a base de dados
*/
int rc = 0; /* nmero de processos lendo ou
querendo ler */

void* reader(void *arg);
void* writer(void *arg);
void read_data_base();
void use_data_read();
void think_up_data();
void write_data_base();

int main() {
sem_init(&mutex, 0, 1);
sem_init(&db, 0, 1);

pthread_t r[3], w[2];

int i;

/* criando leitores */
for (i = 0; i < 3 ; i++) {
pthread_create(&r[i], NULL, reader, (void*) &i);
}

/* criando escritores */
for (i = 0; i< 2; i++) {
pthread_create(&w[i], NULL, writer, (void*) &i);
}

while(TRUE);
return 0;
}

void* reader(void *arg) {
int i = *((int *) arg);

while(TRUE) { /* repere para sempre */
sem_wait(&mutex); /* obtm acesso exclusivo 'rc' */
rc = rc + 1; /* um leitor a mais agora */

if (rc == 1) { /* se este for o primeiro leitor... */
sem_wait(&db);
}

sem_post(&mutex); /* libera o acesso exclusivo a 'rc' */
read_data_base(i); /* acesso aos dados */
sem_wait(&mutex); /* obtm acesso exclusivo a 'rc' */
rc = rc - 1; /* um leitor a menos agora */

if (rc == 0) { /* se este for o ltimo leitor */
sem_post(&db);
}

sem_post(&mutex); /* libera o acesso exclusivo a 'rc' */
use_data_read(i); /* regio no crtica */
}
}

void* writer(void *arg) {
int i = *((int *) arg);

while(TRUE) { /* repete para sempre */
think_up_data(i); /* regio no crtica */
sem_wait(&db); /* obtm acesso exclusivo */
write_data_base(i); /* atualiza os dados */
sem_post(&db); /* libera o acesso exclusivo */
}
}

void read_data_base(int i) {
printf("Reader %d estah lendo os dados!\n", i);
sleep( rand() % 5);
}

void use_data_read(int i) {
printf("Reader %d estah usando os dados lidos!\n", i);
sleep(rand() % 5);
}

void think_up_data(int i) {
printf("Writer %d estah pensando no que escrever!\n", i);
sleep(rand() % 5);
}

void write_data_base(int i) {
printf("Writer %d estah escrevendo os dados!\n", i);
sleep( rand() % 5);
}

O Problema do Barbeiro Dorminhoco (com threads)
Em cincia da computao, o problema do barbeiro dorminhoco um
problema clssico de comunicao inter-processo e sincronizao entre
mltiplos processos.
O problema anlogo a manter o barbeiro ocupado enquanto h clientes, e
descansando quando no h nenhum (fazendo isso de uma maneira
ordenada).
O barbeiro e seus clientes correspondem aos processos mencionados acima.
O problema:
Na barbearia h um barbeiro, uma cadeira de barbeiro e n cadeiras para
eventuais clientes esperarem a vez. Quando no h clientes, o barbeiro
senta-se na cadeira de barbeiro e cai no sono. Quando chega um cliente, ele
precisa acordar o barbeiro. Se outros clientes chegarem enquanto o barbeiro
estiver cortando o cabelo de um cliente, eles se sentaro (se houver cadeiras
vazias) ou sairo da barbearia (se todas as cadeiras estiverem ocupadas). O
problema programar o barbeiro e os clientes sem cair em condies de
disputa. Esse problema semelhante a situaes com vrias filas, como uma
mesa de atendimento de telemarketing com diversos atendentes e com um
sistema computadorizado de chamadas em espera, atendendo a um nmero
limitado de chamadas que chegam.
A soluo aqui apresentada usa trs semforos: customers, que conta os
clientes espera de atendimento (exceto o cliente que est na cadeira de
barbeiro, que no est esperando); barbers, o nmero de barbeiros (0 ou 1)
que esto ociosos espera de clientes, e mutex, que usado para excluso
mtua. Precisamos ainda de uma varivel,waiting, que tambm conta os
clientes espera de atendimento. essencialmente uma cpia de customers.
A razo de se ter waiting que no h uma maneira de ler o valor atual do
semforo. Nessa soluo, um cliente que entra na barbearia deve contar o
nmero de clientes espera de atendimento. Se este for menor que o nmero
de cadeiras, ele ficar; do contrrio, ele sair.
Na soluo, quando chega de manh para trabalhar, o barbeiro executa o
mtodo barber, que o leva a bloquear sobre o semforo customers,que
inicialmente est em 0. O barbeiro ento vai dormir, e permanece dormindo
at que o primeiro cliente aparea.
Quando chega, o cliente executa customer e inicia obtendo mutex para entrar
em uma regio crtica. Se um outro cliente chega logo em seguida, o segundo
nada pode fazer at que o primeiro libere o mutex.O cliente ento verifica se
o nmero de clientes espera menor que o nmero de cadeiras. Se no
for, ele liberar o mutex e sair sem cortar o cabelo.
Se houver uma cadeira disponvel, o cliente incrementar a varivel
inteira waiting. Ele faz ento um up no semforo customers, que acorda o
barbeiro. Nesse ponto, o cliente e o barbeiro esto ambos acordados. Quando
o cliente libera mutex, o barbeiro o pega, faz alguma limpeza e comea a
cortar o cabelo.
Quando termina o corte de cabelo, o cliente sai do procedimento e deixa a
barbearia. Diferente de nossos exemplos anteriores, no h um lao para o
cliente porque para cada um deles ter apenas um corte de cabelo. O
barbeiro, contudo, contm um lao para tentar obter o prximo cliente. Se
houver algum outro cliente, um novo corte de cabelo ser iniciado. Do
contrrio, o barbeiro cair no sono.
Abaixo est a implementao do problema, com os resultados obtidos:


Sada do Programa barbeiro.c
Cdigo:

#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
#include "pthread.h"
#include "semaphore.h"

#define CHAIRS 5 /* nmero de cadeiras para os clientes
espera */
#define TRUE 1

sem_t customers; /* nmero de cliente espera de
atendimento */
sem_t barbers; /* nmero de barbeiros espera de
clientes */
sem_t mutex; /* para excluso mtua */
int waiting = 0; /* clientes que esto esperando (no
esto cortando) */

/* prottipos */
void* barber(void *arg);
void* customer(void *arg);
void cut_hair();
void customer_arrived();
void get_haircut();
void giveup_haircut();

int main() {
sem_init(&customers, TRUE, 0);
sem_init(&barbers, TRUE, 0);
sem_init(&mutex, TRUE, 1);

pthread_t b, c;

/* criando nico barbeiro */
pthread_create(&b, NULL, (void *) barber, NULL);


/* criao indefinida de clientes */
while(TRUE) {
pthread_create(&c, NULL, (void *) customer, NULL);
sleep(1);
}

return 0;
}

void* barber(void *arg) {
while(TRUE) {
sem_wait(&customers); /* vai dormir se o nmero de clientes for 0 */
sem_wait(&mutex); /* obtm acesso a 'waiting' */
waiting = waiting - 1; /*descresce de um o contador de clientes
espera */
sem_post(&barbers); /* um barbeiro est agora pronto para cortar
cabelo */
sem_post(&mutex); /* libera 'waiting' */
cut_hair(); /* corta o cabelo (fora da regio crtica) */
}

pthread_exit(NULL);
}

void* customer(void *arg) {
sem_wait(&mutex); /* entra na regio crtica */

if(waiting < CHAIRS) { /* se no houver cadeiras vazias, saia */
customer_arrived();
waiting = waiting + 1; /* incrementa o contador de clientes espera
*/
sem_post(&customers); /* acorda o barbeiro se necessrio */
sem_post(&mutex); /* libera o acesso a 'waiting' */
sem_wait(&barbers); /* vai dormir se o nmero de barbeiros livres
for 0 */
get_haircut(); /* sentado e sendo servido */
} else {
sem_post(&mutex); /* a barbearia est cheia; no espera */
giveup_haircut();

}

pthread_exit(NULL);
}

void cut_hair() {
printf("Barbeiro estah cortando o cabelo de alguem!\n");
sleep(3);
}

void customer_arrived() {
printf("Cliente chegou para cortar cabelo!\n");
}
void get_haircut() {
printf("Cliente estah tendo o cabelo cortado!\n");
}

void giveup_haircut() {
printf("Cliente desistiu! (O salao estah muito cheio!)\n");
}




































Bibliografia:

Blog de CES33 Sistemas Operacionais ITA T.10
<http://ces33.blogspot.com.br/>











































Isabela Ilma Gonalves 3 Anlise e Desenvolvimento de Sistemas / Manh

Você também pode gostar