Sistemas Operacionais Processos Semáforos Semáforos Mecanismo de sincronização que não requer espera ocupada Dijkstra propôs usar uma variável inteira para contar o n o de WAKEUPs para uso futuro Menos complicado Esta variável, denominada semáforo, pode ter valor 0 (nenhum WAKEUP pendente) ou um valor inteiro positivo Apenas duas operações são definidas sobre estas variáveis: as operações P (Down) e V (Up) 2 Comunicação e Sincronização 1
(cont.) Semáforos P(s) (Down) - checa o valor do semáforo. Se o valor é maior que 0 (zero), decrementa e continua. Se for igual a 0, o processo é posto para dormir Ação atômica: é garantido que, uma vez iniciada a operação, nenhum outro processo tem acesso ao semáforo (essencial para resolver problemas de sincronização e evitar condições de corrida) P(s) equivale a: Se s > 0 então s := s - 1 senão bloqueia o processo até s > 0 (= wait(s)) V(s) (Up) - se um ou mais processos estão dormindo no semáforo, um deles é escolhido aleatoriamente pelo SO e continua sua operação Down (o valor zero continua). Se não há ninguém dormindo no semáforo, incrementa o valor dele Operação também é indivisível V(s) equivale a: Verifica se existe uma lista com processos bloqueados por causa de s, se existe escolhe um e o acorda, deixando-o pronto para seguir sua execução de P(s) (= signal(s)) senão s := s + 1 3 Comunicação e Sincronização Semáforos como um mecanismo de sincronização geral Semáforo Contador valor inteiro positivo pode variar sem limites Semáforo Binário valor inteiro só pode variar entre 0 e 1; Também conhecido como mutex locks Para fornecer exclusão mútua: Semaphore S; // initialized to 1 P(S); criticalsection(); V(S); 4 Comunicação e Sincronização 2
Deadlock e Starvation Deadlock dois ou mais processos ficam esperando indefinidamente por um evento que pode ser causado apenas por um dos processos bloqueados Sejam S e Q dois semáforos inicializados com 1 P 0 P 1 P(S); P(Q); P(Q);...... V(S); V(Q); P(S); V(Q); V(S); Starvation bloqueio indefinido. Um processo pode nunca ser removido da fila de semáforos na qual ele está bloqueado. 5 Comunicação e Sincronização Problema do Produtor-Consumidor Dois processos compartilham um buffer de tamanho fixo. Um dos processos, o produtor, coloca informação no buffer, e o outro, o consumidor, retira informação do buffer. Se o buffer estiver cheio, o produtor dorme e é acordado quando o consumidor remover um item Se o buffer estiver vazio, o consumidor dorme até que seja produzido e armazenado algum item 6 Comunicação e Sincronização 3
Produtor/Consumidor com Semáforos #define N 100 /* no máximo de ítens */ typedef int semaphore; semaphore mutex = 1; /* controla acesso à RC */ semaphore empty = N; /* conta slots vazios */ semaphore full = 0; /* conta slots ocupados */ void producer (void) int item; while (TRUE) produce_item(&item); P(&empty); P(&mutex); enter_item(item); V(&mutex); V(&full); void consumer(void) int item; while (TRUE) P(&full); P(&mutex); remove_item(&item); V(&mutex); V(&empty); consume_item(item); 7 Comunicação e Sincronização Bounded-Buffer Buffer Problem public class BoundedBuffer implements Buffer private static final int BUFFER SIZE = 5; private Object[] buffer; private int in, out; private Semaphore mutex; private Semaphore empty; private Semaphore full; // Continued on next Slide 8 Comunicação e Sincronização 4
Bounded Buffer Constructor public BoundedBuffer() // buffer is initially empty in = 0; out = 0; buffer = new Object[BUFFER SIZE]; mutex = new Semaphore(1); empty = new Semaphore(BUFFER SIZE); full = new Semaphore(0); public void insert(object item) /* next slides */ public Object remove() /* next slides */ 9 Comunicação e Sincronização Bounded Buffer Problem: insert() Method public void insert(object item) empty.acquire(); mutex.acquire(); // add an item to the buffer buffer[in] = item; in = (in + 1) % BUFFER SIZE; mutex.release(); full.release(); 10 Comunicação e Sincronização 5
Bounded Buffer Problem: remove() Method public Object remove() full.acquire(); mutex.acquire(); // remove an item from the buffer Object item = buffer[out]; out = (out + 1) % BUFFER SIZE; mutex.release(); empty.release(); return item; 11 Comunicação e Sincronização Bounded Buffer Problem: Producer import java.util.date; public class Producer implements Runnable private Buffer buffer; public Producer(Buffer buffer) this.buffer = buffer; public void run() Date message; while (true) // nap for awhile SleepUtilities.nap(); // produce an item & enter it into the buffer message = new Date(); buffer.insert(message); 12 Comunicação e Sincronização 6
Bounded Buffer Problem: Consumer import java.util.date; public class Consumer implements Runnable private Buffer buffer; public Consumer(Buffer buffer) this.buffer = buffer; public void run() Date message; while (true) // nap for awhile SleepUtilities.nap(); // consume an item from the buffer message = (Date)buffer.remove(); 13 Comunicação e Sincronização Bounded Buffer Problem: Factory public class Factory public static void main(string args[]) Buffer buffer = new BoundedBuffer(); // now create the producer and consumer threads Thread producer = new Thread(new Producer(buffer)); Thread consumer = new Thread(new Consumer(buffer)); producer.start(); consumer.start(); 14 Comunicação e Sincronização 7