Você está na página 1de 57

Capítulo 5: Sincronização

de Processos

Operating System Concepts – 9th Edition 5.1 Silberschatz, Galvin and Gagne ©2013
Sobre a apresentação (About the slides)

Os slides e figuras dessa apresentação foram criados por Silberschatz, Galvin


e Gagne em 2009. Esta apresentação foi modificada por Cristiano Costa
(cac@unisinos.br). Basicamente, os slides originais foram traduzidos para o
Português do Brasil. Esta apresentação foi atualizada para a Nona Edição do
livro lançada em 2013 por Ronaldo Ferreira (raf@facom.ufms.br).
É possível acessar os slides originais em http://www.os-book.com
A versão de 2009 pode ser obtida em http://www.inf.unisinos.br/~cac

The slides and figures in this presentation are copyright Silberschatz, Galvin
and Gagne, 2009. This presentation has been modified by Cristiano Costa
(cac@unisinos.br). Basically it was translated to Brazilian Portuguese. This
presentation has been updated to the 9th edition of the book released in 2013.
You can access the original slides at http://www.os-book.com
The 2009 version can be downloaded at http://www.inf.unisinos.br/~cac

Operating System Concepts – 9th Edition 5.2 Silberschatz, Galvin and Gagne ©2013
Módulo 5: Sincronização de Processos

! Fundamentos
! O problema da Seção Crítica
! Solução de Peterson
! Hardware de Sincronização
! Mutex Locks
! Semáforos
! Problemas Clássicos de Sincronização
! Monitores

Operating System Concepts – 9th Edition 5.3 Silberschatz, Galvin and Gagne ©2013
Objetivos
! Introduzir o problema da seção crítica, em que as soluções podem ser
usadas para garantir a consistência de dados compartilhados

! Apresentar soluções tanto de software quanto de hardware para o


problema da seção crítica

Operating System Concepts – 9th Edition 5.4 Silberschatz, Galvin and Gagne ©2013
Fundamentos
! Processos podem executar concorrentemente.
" Podem ser interrompidos em qualquer instante de tempo, completando
apenas parcialmente a execução.

! Acesso concorrente a dados compartilhados pode resultar em


inconsistências.

! Manter a consistência de dados requer a utilização de mecanismos para


garantir a execução ordenada de processos cooperantes.

! Suponha que seja desejado fornecer uma solução para o problema do


produtor-consumidor que utilize todo o buffer. É possível fazer isso tendo um
inteiro counter que mantém o número de posições ocupadas no buffer.
Inicialmente, counter é inicializado em 0. Ele é incrementado pelo produtor
após a produção de um novo item e decrementado pelo consumidor após a
retirada.

Operating System Concepts – 9th Edition 5.5 Silberschatz, Galvin and Gagne ©2013
Produtor

while (true) {

/* produz um item e coloca em next_produced */


while (counter == BUFFER_SIZE)
; // do nothing
buffer [in] = next_produced;
in = (in + 1) % BUFFER_SIZE;
counter++;
}

Operating System Concepts – 9th Edition 5.6 Silberschatz, Galvin and Gagne ©2013
Consumidor

while (true) {
while (counter == 0)
; // não faz nada
next_consumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
counter--;
/* consome o item em next_consumed
}

Operating System Concepts – 9th Edition 5.7 Silberschatz, Galvin and Gagne ©2013
Condição de Corrida
! counter++ pode ser implementado como

register1 = counter
register1 = register1 + 1
counter = register1
! counter-- pode ser implementado como

register2 = counter
register2 = register2 - 1
counter = register2
! Considere a seguinte ordem de execução com “counter = 5” inicialmente:
S0: producer execute register1 = counter {register1 = 5}
S1: producer execute register1 = register1 + 1 {register1 = 6}
S2: consumer execute register2 = counter {register2 = 5}
S3: consumer execute register2 = register2 - 1 {register2 = 4}
S4: producer execute counter = register1 {counter = 6 }
S5: consumer execute counter = register2 {counter = 4}

Operating System Concepts – 9th Edition 5.8 Silberschatz, Galvin and Gagne ©2013
Problema da Seção Crítica
! Considere um sistema com n processos {p0, p1, … pn-1}
! Cada um dos n processos possui um segmento de código que
é uma seção crítica
" O processo pode mudar variável, atualizar uma tabela,
escrever em arquivo, etc
" Quando um processo está na seção crítica, nenhum outro
pode estar na sua seção crítica
! O problema da seção crítica é projetar um protocolo para
resolver essa situação
! Cada processo deve pedir permissão para entrar na seção
crítica (na seção de entrada), seguir a seção crítica com uma
seção de saída, então executar a seção restante.

Operating System Concepts – 9th Edition 5.9 Silberschatz, Galvin and Gagne ©2013
Solução para o Problema da Seção Crítica

1. Exclusão Mútua - Se um processo Pi está executando sua seção


crítica, então nenhuma seção crítica de outro processo pode
estar sendo executada.
2. Progresso - Se nenhum processo está executando uma seção
crítica e existem processos que desejam entrar nas seções
críticas deles, então a escolha do próximo processo que irá entrar
na seção crítica não pode ser adiada indefinidamente.
3. Espera Limitada - Existe um limite para o número de vezes que
outros processos são selecionados para entrar nas seções
críticas deles, depois que um processo fez uma requisição para
entrar em sua seção e antes que essa requisição seja atendida.
— É assumido que cada processo executa em uma velocidade
diferente de zero
— Nenhuma hipótese é feita referente à velocidade relativa de
execução dos N processos.

Operating System Concepts – 9th Edition 5.10 Silberschatz, Galvin and Gagne ©2013
Solução para o Problema da Seção Crítica

1. Dois (ou mais) processos não podem estar simultaneamente em


suas seções críticas.
2. Hipótese alguma pode ser feita sobre velocidades ou quantidade
de processadores.
3. Nenhum processo executando fora de sua seção crítica pode
bloquear outro processo.
4. Nenhum processo deve esperar indeterminadamente para entrar
em sua seção crítica.

Operating System Concepts – 9th Edition 5.11 Silberschatz, Galvin and Gagne ©2013
Seção Crítica

! Estrutura geral do processo Pi

Operating System Concepts – 9th Edition 5.12 Silberschatz, Galvin and Gagne ©2013
Desabilitação de Interrupção
! Em sistemas com um único processador, a solução mais simples é fazer
com que cada processo desabilite interrupções no início da seção crítica e
as reabilite antes de deixar sua seção crítica.
! Com interrupções desabilitadas, interrupções do temporizador não podem
ocorrer e não há troca de processos.
! Esta abordagem é problemática porque processos de usuário podem não
habilitar as interrupções novamente. Além disso, ela não funciona em
sistemas com múltiplos processadores.
! É uma solução conveniente para o kernel em sistemas com um único
processador.

Operating System Concepts – 9th Edition 5.13 Silberschatz, Galvin and Gagne ©2013
Tentativas de Solução
para o Problema da Seção Crítica
! Inicialmente serão consideradas soluções para dois processos apenas.

! É assumido que as instruções de máquina LOAD (carrega) e STORE


(armazena) são atômicas; i.e., não podem ser interrompidas.

! Inicialmente são apresentadas duas tentativas e depois a solução.

Operating System Concepts – 9th Edition 5.14 Silberschatz, Galvin and Gagne ©2013
Tentativa 1 – Com Espera Ocupada
(Busy Waiting)

! Variáveis compartilhadas:
" var turn: (0..1);
inicialmente turn = 0
" turn = i Þ Pi pode entrar na sua seção crítica. j = 1 - i
! Processo Pi
do {
while turn != i
; /* não faz nada */
// SEÇÃO CRÍTICA
turn = j;
// SEÇÃO RESTANTE
} while (TRUE);
! Satisfaz exclusão mútua, mas não progresso.

Operating System Concepts – 9th Edition 5.15 Silberschatz, Galvin and Gagne ©2013
Tentativa 2 – Com Espera Ocupada
(Busy Waiting)

! Variáveis compartilhadas:
" var flag: array [0..1] of boolean;
inicialmente flag [0] = flag [1] = false.
" flag [i] = true Þ Pi pronto para entrar na seção crítica. j = 1 - i
! Processo Pi
do {
flag[i] = true;
while flag[j]
; /* não faz nada */
// SEÇÃO CRÍTICA
flag [i] = false;
// SEÇÃO RESTANTE
} while (TRUE);
! Satisfaz exclusão mútua, mas não progresso.

Operating System Concepts – 9th Edition 5.16 Silberschatz, Galvin and Gagne ©2013
Solução de Peterson
! Os dois processos compartilham duas variáveis:
" int turn;
" Boolean flag[2]

! A variável turn indica de quem é a vez de entrar na seção


crítica.

! O vetor flag é usado para indicar se um processo está


pronto para entrar na seção crítica. flag[i] = true significa
que processo Pi está pronto!

Operating System Concepts – 9th Edition 5.17 Silberschatz, Galvin and Gagne ©2013
Algoritmo Para Processo Pi

do {
flag[i] = TRUE;
turn = j;
while ( flag[j] && turn == j)
; /* não faz nada */
// SEÇÃO CRÍTICA
flag[i] = FALSE;
// SEÇÃO RESTANTE
} while (TRUE);

Operating System Concepts – 9th Edition 5.18 Silberschatz, Galvin and Gagne ©2013
Sincronização por Hardware
! Muitos sistemas fornecem suporte de hardware para código de
seção crítica
! Todas as soluções a seguir são baseadas na ideia de locking
" Protege seções críticas via locks
! Sistemas Monoprocessados – podem desabilitar interrupções
" Código em execução pode executar sem preempção
" Geralmente muito ineficiente em sistemas multiprocessados
4Sistemas Operacionais que usam isso não escalam
! Arquiteturas modernas fornecem instruções atômicas especiais
de hardware
4Atômica = não interrompível
" Testar uma posição de memória e setar um valor
" Ou trocar conteúdos de duas posições na memória

Operating System Concepts – 9th Edition 5.19 Silberschatz, Galvin and Gagne ©2013
Solução para o Problema da Seção Crítica
usando Locks

do {
adquire lock
seção crítica
libera lock
seção restante
} while (TRUE);

Operating System Concepts – 9th Edition 5.20 Silberschatz, Galvin and Gagne ©2013
Instrução test_and_set

! Definição:

boolean test_and_set (boolean *target)


{
boolean rv = *target;
*target = TRUE;
return rv:
}

1. Executada de forma atômica. Bloqueia


2. Retorna o valor original passado como parâmetro
3. Atribui TRUE à varíavel passada como parâmetro

Operating System Concepts – 9th Edition 5.21 Silberschatz, Galvin and Gagne ©2013
Solução usando test_and_set

! Variável booleana compartilhada lock, inicializada em FALSE.


! Solução:

while (true) {
while ( test_and_set (&lock ))
; /* não faz nada */
// SECÃO CRÍTICA
lock = FALSE;
// SEÇÃO RESTANTE
}

Operating System Concepts – 9th Edition 5.22 Silberschatz, Galvin and Gagne ©2013
Instrução compare_and_swap

! Definição:
void compare_and_swap (int *value, int expected, int new_value)
{
int temp = *value;

if (*value == expected)
*value = new_value;
return temp:
}

1. Executada de forma atômica


2. Retorna o valor original passado como parâmetro
3. Atribui à varíavel value o valor new_value se “value == expected”. Ou
seja, a troca ocorre somente nesta condição.

Operating System Concepts – 9th Edition 5.23 Silberschatz, Galvin and Gagne ©2013
Solução usando compare_and_swap
! Variável booleana compartilhada lock, inicializada em FALSE; Cada
processo tem uma variável booleana key local.
! Solução:
do {
while (compare_and_swap(&lock, FALSE, TRUE) != FALSE)
; // Não faz nada
// SEÇÃO CRÍTICA
lock = FALSE;
// SEÇÃO RESTANTE
} while (TRUE)

Operating System Concepts – 9th Edition 5.24 Silberschatz, Galvin and Gagne ©2013
Exclusão Mútua com Espera Limitada
usando test_and_set()

do {
waiting[i] = TRUE;
key = 1;
while (waiting[i] && key == 1)
key = test_and_set(&lock); // or compare_and_swap(&lock, 0, 1);
waiting[i] = FALSE;
// critical section
j = (i + 1) % n;
while ((j != i) && !waiting[j])
j = (j + 1) % n;
if (j == i)
lock = FALSE;
else
waiting[j] = FALSE;
// remainder section
} while (TRUE);

Operating System Concepts – 9th Edition 5.25 Silberschatz, Galvin and Gagne ©2013
Mutex Locks
! As soluções anteriores são complicadas e geralmente inacessíveis aos
programadores de aplicação

! Os projetistas de SO constroem ferramentas de software para resolver o


problema da seção crítica

! A solução mais simples é o mutex lock

! Protege a seção crítica primeiro adquirindo (acquire()) um lock e depois


liberando (release()) o lock
" Variável booleana indica se o lock está disponível ou não

! Chamadas para as funções acquire()e release()devem ser atômicas


" Geralmente implementadas via instruções de hardware

! Mas essa solução requer espera ocupada (busy waiting)


" Esse tipo de lock é chamado de spinlock

Operating System Concepts – 9th Edition 5.26 Silberschatz, Galvin and Gagne ©2013
acquire() e release()
acquire() {
while (!available)
; /* busy wait */
available = false;;
}
release() {
available = true;
}
do {
acquire lock
critical section
release lock
remainder section
} while (true);

Operating System Concepts – 9th Edition 5.27 Silberschatz, Galvin and Gagne ©2013
Semáforo
! Ferramenta de sincronização que não requer espera ocupada (busy waiting)
! Semáforo S – variável inteira
! Duas operações padrão modificam S: wait() e signal()
" Originalmente chamadas P() e V()
! Menos Complicada
! Somente pode ser acessada via duas operações indivisíveis (atômicas)
" wait (S) {
while S <= 0
; // não faz nada
S--;
}
" signal (S) {
S++;
}

Operating System Concepts – 9th Edition 5.28 Silberschatz, Galvin and Gagne ©2013
Semáforo como uma Ferramenta Geral de Sincronização

! Semáforo Contador – valor nele armazenado pode ser qualquer número


inteiro.
! Semáforo Binário – valor inteiro nele armazenado pode variar entre 0 e 1;
pode ser implementado mais simplesmente.
" Também conhecido como mutex locks
! É possível implementar semáforo contador S como um semáforo binário
! Fornece exclusão mútua:
semaphore mutex; // inicializado em 1
do {
wait (mutex);
// Seção Crítica
signal (mutex);
// restante do código
} while (TRUE);

Operating System Concepts – 9th Edition 5.29 Silberschatz, Galvin and Gagne ©2013
Implementação de Semáforo

! Deve garantir que dois processos não possam executar wait ()


e signal () no mesmo semáforo ao mesmo tempo

! Daí, a implementação se torna o problema da seção crítica na


qual o código do wait e signal são colocados em seções
críticas.
" Pode ter espera ocupada na implementação da seção
crítica
4Código de implementação é menor
4Pequena espera ocupada se seção crítica está sendo
usada raramente

! Observe que aplicações podem perder muito tempo em


seções críticas e daí esta não é uma boa solução.

Operating System Concepts – 9th Edition 5.30 Silberschatz, Galvin and Gagne ©2013
Implementação de Semáforo sem Espera Ocupada

! Associar uma fila de espera com cada semáforo. Cada entrada


na fila de espera tem dois itens:
" valor (de tipo inteiro)
" ponteiro para o próximo registro na lista
! Duas operações:
" block – coloca o processo que evoca a operação na fila de
espera apropriada.
" wakeup – remove um processo da fila de espera e coloca-
o na fila de processos prontos (ready queue).

typedef struct{
int value;
struct process *list;
} semaphore;

Operating System Concepts – 9th Edition 5.31 Silberschatz, Galvin and Gagne ©2013
Implementação de Semáforo sem Espera Ocupada (Cont.)

! Implementação de wait:
wait(semaphore *S) {
S->value--;
if (S->value < 0) {
adiciona esse processo em S->list;
block();
}
}
! Implementação de signal:
signal(semaphore *S) {
S->value++;
if (S->value <= 0) {
remove o processo P de S->list;
wakeup(P);
}
}

Operating System Concepts – 9th Edition 5.32 Silberschatz, Galvin and Gagne ©2013
Deadlock (Impasse) e Starvation (Abandono)

! Deadlock – dois ou mais processos estão esperando indefinidamente por


um evento que pode ser causado somente por um dos processos
esperando o evento
! Seja S e Q dois semáforos inicializados em 1
P0 P1
wait (S); wait (Q);
wait (Q); wait (S);
... ...
signal (S); signal (Q);
signal (Q); signal (S);
! Starvation – bloqueio indefinido. Um processo pode nunca ser removido
da fila do semáforo em que está suspenso
! Priority Inversion – inversão de prioridade. Problema de escalonamento em
que um processo de baixa prioridade mantém um lock necessário para
um processo de maior prioridade
" Este problema pode ser resolvido pelo protocolo de herança de
prioridade (priority-inheritance protocol)

Operating System Concepts – 9th Edition 5.33 Silberschatz, Galvin and Gagne ©2013
Inversão de Prioridade
! Priority Inversion – inversão de prioridade. Problema de escalonamento em
que um processo de baixa prioridade mantém um lock necessário para
um processo de maior prioridade
" Considere processos L < M < H e que o processo H precisa de um
semáforo que está com L.
" Suponha agora que M fique pronto e colocado em execução,
preemptando L. Indiretamente, M (menor prioridade) está afetando o
tempo que H (maior prioridade) fica esperando.
" Este problema pode ser resolvido pelo protocolo de herança de
prioridade (priority-inheritance protocol) em que um processo que está
acessando um semáforo herda a prioridade de outro processo de maior
prioridade quando.

Operating System Concepts – 9th Edition 5.34 Silberschatz, Galvin and Gagne ©2013
Problemas com Semáforos

! Uso incorreto de operações em semáforos:

" signal (mutex) …. wait (mutex)

" wait (mutex) … wait (mutex)

" Omissão de wait (mutex) ou signal (mutex) (ou ambos)


! Deadlock e starvation são possíveis.

Operating System Concepts – 9th Edition 5.35 Silberschatz, Galvin and Gagne ©2013
Monitores
! Abstração de alto nível que fornece um mecanismo conveniente e
eficiente para sincronização de processos
! Tipo abstrato de dados (ADT). Variáveis internas são acessíveis
apenas pelo código dentro do procedimento.
! Somente um processo por vez pode estar ativo dentro do monitor
monitor nome-monitor
{
// declaração de variáveis compartilhadas
procedure P1 (…) { …. }

procedure Pn (…) {……}

Código de Inicialização ( ….) { … }



}
}

Operating System Concepts – 9th Edition 5.36 Silberschatz, Galvin and Gagne ©2013
Visão Esquemática de um Monitor

Operating System Concepts – 9th Edition 5.37 Silberschatz, Galvin and Gagne ©2013
Variáveis Condicionais

! condition x, y;

! Duas operações em variáveis condicionais:


" x.wait () – um processo que invoca essa operação é
suspenso até x.signal ().
" x.signal () – reinicia um dos processos (se existe algum)
que invocou x.wait ().
" Se não há um x.wait () pendente, então não produz
efeito algum na variável

Operating System Concepts – 9th Edition 5.38 Silberschatz, Galvin and Gagne ©2013
Monitor com Variáveis Condicionais

Operating System Concepts – 9th Edition 5.39 Silberschatz, Galvin and Gagne ©2013
Pthreads

! Algumas chamadas da biblioteca Pthreads relacioinadas


a mutexes.

Thread Call Description


pthread_mutex_init Cria um mutex
pthread_mutex_destroy Destrói um mutex
pthread _mutex_lock Adquire um lock ou bloqueia
pthread_mutex_trylock Adquire um lock ou falha
pthread_mutex_unlock Libera um lock

Operating System Concepts – 9th Edition 5.40 Silberschatz, Galvin and Gagne ©2013
Pthreads

! Algumas chamadas da biblioteca Pthreads relacionadas


a variáveis condicionais.

Thread Call Description


pthread_cond_init Cria uma variável condicional
pthread_cond_destroy Destroi uma var. condicional
pthread _cond_wait Bloqueia a espera de um sinal
pthread_cond_signal Sinaliza e acorda uma outra thread
pthread_cond_broadcast Sinaliza e acorda múltiplas threads

Operating System Concepts – 9th Edition 5.41 Silberschatz, Galvin and Gagne ©2013
Variáveis Condicionais

! Variáveis condicionais são sempre usadas em conjunto com


mutexes.
! O padrão é fazer uma thread adquirir um mutex e então wait ()
em uma variável condicional quando a thread não conseguir
fazer o que precisa.
! Eventualmente, uma outra thread sinaliza (signal () ) a thread
bloqueada para que ela possa continuar.
! A chamada pthread_cond_wait desloqueia atomicamente o
mutex que ela detém. Por essa razão, o mutex é um de seus
parâmetros.

Operating System Concepts – 9th Edition 5.42 Silberschatz, Galvin and Gagne ©2013
pthread cond signal(&condp);
pthread mutex unlock(&the mutex)
}
138
Variáveis Condicionais
PROCESSES AND THREADS CHAP. 2

}
pthread exit(0);

#include <stdio.h>
#include <pthread.h> int main(int argc, char **argv)
{
#define MAX 1000000000 /* how many numbers to produce */
pthread t pro, con;
pthread mutex t the mutex;
pthread cond t condc, condp; /* used for signaling */ pthread mutex init(&the mutex, 0);
int buffer = 0; /* buffer used between producer and consumer */ pthread cond init(&condc, 0);
pthread cond init(&condp, 0);
void *producer(void *ptr) /* produce data */
{ int i; pthread create(&con, 0, consumer, 0);
pthread create(&pro, 0, producer, 0);
for (i= 1; i <= MAX; i++) { pthread join(pro, 0);
pthread mutex lock(&the mutex); /* get exclusive access to buffer */
while (buffer != 0) pthread cond wait(&condp, &the mutex);
pthread join(con, 0);
buffer = i; /* put item in buffer */ pthread cond destroy(&condc);
pthread cond signal(&condc); /* wake up consumer */ pthread cond destroy(&condp);
pthread mutex unlock(&the mutex); /* release access to buffer */ pthread mutex destroy(&the mutex);
} }
pthread exit(0);
}

void *consumer(void *ptr) /* consume data */ Figure 2-32. Using threads to solve the pr
{ int i;
for (i = 1; i <= MAX; i++) {
pthread mutex lock(&the mutex); /* get exclusive access to buffer */
while (buffer ==0 ) pthread cond wait(&condc, &the mutex);
buffer = 0; /* take item out of buffer */
pthread cond signal(&condp); /* wake up producer */
pthread mutex unlock(&the mutex); /* release access to buffer */
}
pthread exit(0);
}

int main(int argc, char **argv)


{
pthread t pro, con;
pthread mutex init(&the mutex, 0);
pthread cond init(&condc, 0);
pthread
Operating condConcepts
System init(&condp,
– 9th0);
Edition 5.43 Silberschatz, Galvin and Gagne ©2013
mon.inser t(item);
}
}
private int produce item( ) { ... } // actually produce

142 Monitor em Java


PROCESSES AND THREADS
}
CHAP. 2
static class consumer extends Thread {
public void run( ) { run method contains the thread code
public class ProducerConsumer { int item;
static final int N = 100; // constant giving the buffer size
while (true) { // consumer loop
static producer p = new producer( ); // instantiate a new producer thread
item = mon.remove( );
static consumer c = new consumer( ); // instantiate a new consumer thread
consume item (item);
static our monitor mon = new our monitor( ); // instantiate a new monitor
}
public static void main(String args[ ]) { }
p.star t( ); // star t the producer thread private void consume item(int item) { ... } // actually consume
c.star t( ); // star t the consumer thread }
}
static class our monitor { // this is a monitor
static class producer extends Thread { private int buffer[ ] = new int[N];
public void run( ) { // run method contains the thread code private int count = 0, lo = 0, hi = 0; // counters and indices
int item;
while (true) { // producer loop public synchronized void insert(int val) {
item = produce item( ); if (count == N) go to sleep( ); // if the buffer is full, go to sleep
mon.inser t(item); buffer [hi] = val; // inser t an item into the buffer
} hi = (hi + 1) % N; // slot to place next item in
} count = count + 1; // one more item in the buffer now
private int produce item( ) { ... } // actually produce if (count == 1) notify( ); // if consumer was sleeping, wake it up
} }
static class consumer extends Thread { public synchronized int remove( ) {
public void run( ) { run method contains the thread code int val;
int item; if (count == 0) go to sleep( ); // if the buffer is empty, go to sleep
while (true) { // consumer loop val = buffer [lo]; // fetch an item from the buffer
item = mon.remove( ); lo = (lo + 1) % N; // slot to fetch next item from
consume item (item); count = count − 1; // one few items in the buffer
}
if (count == N − 1) notify( ); // if producer was sleeping, wake it up
}
return val;
private void consume item(int item) { ... } // actually consume
}
}
private void go to sleep( ) { try{wait( );} catch(InterruptedException exc) {};}
static class our monitor { // this is a monitor }
private int buffer[ ] = new int[N]; }
private int count = 0, lo = 0, hi = 0; // counters and indices Figure 2-35. A solution to the producer-consumer problem in Java.
public synchronized void insert(int val) {
if (count == N) go to sleep( ); // if the buffer is full, go to sleep
buffer [hi] = val; // inser t an item into the buffer
hi = (hi + 1) % N; // slot to place next item in
count = count + 1; // one more item in the buffer now
Operating System
if (count Concepts // if consumer was sleeping, wake it 5.44
== 1) notify(– );9th Edition up Silberschatz, Galvin and Gagne ©2013
Problemas Clássicos de Sincronização
! Problema do Buffer de tamanho limitado (Bounded-Buffer)
! Problema dos Leitores e Escritores
! Problema do Jantar dos Filósofos (Dining-Philosophers)

Operating System Concepts – 9th Edition 5.51 Silberschatz, Galvin and Gagne ©2013
Problema do Buffer de Tamanho Limitado

! N posições de memória, cada uma pode armazenar um item

! Semáforo mutex inicializado com o valor 1

! Semáforo full inicializado com o valor 0

! Semáforo empty inicializado com o valor N.

Operating System Concepts – 9th Edition 5.52 Silberschatz, Galvin and Gagne ©2013
Problema do Buffer de Tamanho Limitado (Cont.)

! A estrutura do processo produtor

do {
// produz um item

wait (empty);
wait (mutex);

// adiciona o item ao buffer

signal (mutex);
signal (full);
} while (TRUE)

Operating System Concepts – 9th Edition 5.53 Silberschatz, Galvin and Gagne ©2013
Problema do Buffer de Tamanho Limitado (Cont.)

! A estrutura do processo consumidor

do {
wait (full);
wait (mutex);

// remove um item do buffer

signal (mutex);
signal (empty);

// consome o item removido

} while (TRUE);

Operating System Concepts – 9th Edition 5.54 Silberschatz, Galvin and Gagne ©2013
Problema dos Leitores e Escritores

! Um conjunto de dados é compartilhada entre vários processos


concorrentes
" Leitores – somente lê um conjunto de dados; eles não
realizam nenhuma atualização
" Escritores – podem ler e escrever.

! Problema – permitir múltiplos leitores ler ao mesmo tempo.


Somente um único escritor pode acessar os dados
compartilhados ao mesmo tempo.

! Dados Compartilhados
" Conjunto de dados
" Semáforo rw_mutex inicializado em 1.
" Semáforo mutex inicializado em 1.
" Inteiro read_count inicializado em 0.

Operating System Concepts – 9th Edition 5.55 Silberschatz, Galvin and Gagne ©2013
Problema dos Leitores e Escritores (Cont.)

! A estrutura de um processo escritor

do {
wait (rw_mutex) ;

// writing is performed

signal (rw_mutex) ;
} while (TRUE);

Operating System Concepts – 9th Edition 5.56 Silberschatz, Galvin and Gagne ©2013
Problema dos Leitores e Escritores (Cont.)
! A estrutura de um processo leitor

do {
wait (mutex) ;
read_count ++ ;
if (read_count == 1)
wait (rw_mutex) ;
signal (mutex)

// reading is performed

wait (mutex) ;
readcount - - ;
if (read_count == 0)
signal (rw_mutex) ;
signal (mutex) ;
} while (TRUE);

Operating System Concepts – 9th Edition 5.57 Silberschatz, Galvin and Gagne ©2013
Problema do Jantar dos Filósofos

! Filósofos alternam entre pensando e comendo


! Não interagem com seus vizinho, ocasionalmente tentam pegar dois
chopsticks (um por vez) para comer na tigela.
! Dados Compartilhados
" Tigela de Arroz (conjunto de dados)
" Semáforo chopstick [5] inicializados em 1 (5 filósofos)

Operating System Concepts – 9th Edition 5.58 Silberschatz, Galvin and Gagne ©2013
Problema do Jantar dos Filósofos (Cont.)

! A estrutura do Filósofo i:
do {
wait ( chopstick[i] );
wait ( chopStick[ (i + 1) % 5] );

// comer

signal ( chopstick[i] );
signal (chopstick[ (i + 1) % 5] );

// pensar
} while (TRUE);

! Qual o problema com este algoritmo?

Operating System Concepts – 9th Edition 5.59 Silberschatz, Galvin and Gagne ©2013
Solução para o problema dos Filósofos

monitor DP
{
enum { THINKING; HUNGRY, EATING) state [5] ;
condition self [5];

void pickup (int i) {


state[i] = HUNGRY;
test(i);
if (state[i] != EATING) self [i].wait;
}

void putdown (int i) {


state[i] = THINKING;
// test left and right neighbors
test((i + 4) % 5);
test((i + 1) % 5);
}

Operating System Concepts – 9th Edition 5.60 Silberschatz, Galvin and Gagne ©2013
Solução para o problema dos Filósofos (Cont.)

void test (int i) {


if ( (state[(i + 4) % 5] != EATING) &&
(state[i] == HUNGRY) &&
(state[(i + 1) % 5] != EATING) ) {
state[i] = EATING ;
self[i].signal () ;
}
}

initialization_code() {
for (int i = 0; i < 5; i++)
state[i] = THINKING;
}
}

Operating System Concepts – 9th Edition 5.61 Silberschatz, Galvin and Gagne ©2013
Solução para o problema dos Filósofos (Cont.)

! Cada filósofo evoca as operações pickup()


e putdown() na seguinte seqüência:

dp.pickup (i)

COMER

dp.putdown (i)

Operating System Concepts – 9th Edition 5.62 Silberschatz, Galvin and Gagne ©2013
Fim do Capítulo 5

Operating System Concepts – 9th Edition 5.72 Silberschatz, Galvin and Gagne ©2013

Você também pode gostar