Sistemas Operacionais Processos Exclusão Mútua Mecanismos para se Obter Exclusão MútuaM Mecanismos de Hardware: Inibição de Interrupções Instrução TSL (Test and Set Lock) Mecanismos de Software: Com Espera Ocupada: Variáveis de Travamento (Lock Variables) Alternância Estrita Solução de Peterson Sem Espera Ocupada: Dormir e Acordar (Sleep and Wakeup) Semáforos Contadores de Eventos Monitores Troca de Mensagens 2 Comunicação e Sincronização 1
Inibição das Interrupções Solução mais simples Desabilitam-se todas as interrupções após se entrar na região crítica ao sair, reabilitam-nas Se as interrupções não ocorrem, o processo não pode sofrer preempção Problema 1:... e se o processo não reabilitar as interrupções? Problema 2: se o sistema tem 2 CPUs e somente uma tem as interrupções inibidas, a outra pode acessar a memória compartilhada Por outro lado, é muito conveniente que o kernel possa desabilitar as interrupções para atualizar variáveis ou listas Conclusão: solução adequada para o kernel, mas não para processos de usuário 3 Comunicação e Sincronização Instrução TSL (Test( and Set Lock) Instrução especial que permite ler uma variável, armazenar seu conteúdo em uma outra área e atribuir um novo valor a esta variável (hardware) É uma instrução indivisível: executada sem interrupção Variável compartilhada flag: quando flag = 0, qualquer processo pode fazê-la igual a 1 (instrução TSL) 4 Comunicação e Sincronização 2
enter_region: (cont.) Instrução TSL tsl register, flag copia flag p/ cmp register, #0 jnz enter_region ret registrador e faz flag = 1 o flag é zero? se não,lock e setado;loop retorna, entrou na R.C. leave_region: mov flag, #0 ret guarda um 0 em flag retorna a quem chamou 5 Comunicação e Sincronização Variáveis de Travamento (Lock( Variables) Define-se uma única variável compartilhada, inicialmente com valor zero Se um processo deseja entrar na região crítica, ele testa a variável. Se ela for 1 (recurso liberado), ela é feita 0 (recurso trancado) e o processo entra. Caso contrário, o processo aguarda até que o valor da variável seja 1 (um) 6 Comunicação e Sincronização 3
(cont.) Variáveis de Travamento x = 0, recurso trancado x = 1, recurso liberado while (x == 0) do /* nada */; Entrada x = 0; Entrada... Região Crítica x = 1; Saída Problema: Este mecanismo apresenta a falha de que a alteração de valor para trancado, após o teste, permite que dois processos executem a Região Crítica (RC) ao mesmo tempo O teste e a alteração necessitam ser feitos de forma indivisível (atômica) 7 Comunicação e Sincronização Alternância Estrita Processo A while (TRUE) { while (turn!= 0); Reg_Crítica(); turn = 1; Reg_Não_Crítica(); Processo B while (TRUE) { while (turn!= 1); Reg_Crítica(); turn = 0; Reg_Não_Crítica(); Inicialmente a variável turn é feita igual a 0 (zero) Assim, o Processo A consegue entrar na região crítica Enquanto isto, o Processo B ficará continuamente testando a variável (Espera Ocupada) 8 Comunicação e Sincronização 4
(cont.) Alternância Estrita Problema 1: o fato do Processo B ficar fazendo Espera Ocupada deve ser evitado, pois consome tempo de CPU Problema 2: não é uma boa solução quando um processo é muito mais lento que o outro Problema 3: viola a condição de que um processo que não esteja em sua região crítica não bloqueie outro 9 Comunicação e Sincronização Solução de Peterson Antes de entrar na Região Crítica (RC), cada processo chama enter_region com seu n o (0 ou 1) como parâmetro. Ao sair, leave_region #include prototypes.h #define FALSE 0 #define TRUE 1 #define N 2 /* n o de processos */ int turn; /* de quem é a vez */ int interested[n]; /* todos valores inici- */ /* almente 0 (FALSE) */ 10 Comunicação e Sincronização 5
(cont.) Solução de Peterson void enter_region (int process) { /* process = quem está entrando (0 ou 1) */ int other; /* n o do outro processo */ other = 1 - process; /* o outro processo */ interested[process] = TRUE; /* mostra interesse */ turn = process; /* define flag */ while (turn==process && interested[other]==true); void leave_region (int process) { /* process = quem está saindo */ interested[process] = FALSE; /* indica saída RC */ 11 Comunicação e Sincronização Dormir e Acordar (Sleep( and Wakeup) Problema da Solução de Peterson e da Instrução TSL: o processo que não consegue acesso à R.C. permanece em espera ocupada (busy waiting): gasta tempo de processador inutilmente pode provocar o Problema da Inversão de Prioridade: Dois processos A (alta prioridade) e B (baixa prioridade)» B entra na Região Crítica;» A vai para estado de pronto;» A passa para estado de execução;» A fica testando indefinidamente. Chamadas de sistema: SLEEP e WAKEUP 12 Comunicação e Sincronização 6
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 13 Comunicação e Sincronização (?) Solução com SLEEP e WAKEUP #define N 100 /* n o máximo de ítens */ int count = 0; /* n o de ítens no buffer */ Produtor void producer (void) { int item; while (TRUE) { produce_item(&item); if (count==n) sleep(); enter_item(item); count += 1; if (count==1) wakeup(consumer); void consumer(void) { int item; while (TRUE) { if (count==0) sleep(); remove_item(&item); count -= 1; if (count==n-1) wakeup(producer); Consumidor consume_item(item); 14 Comunicação e Sincronização 7
(cont.) Solução com SLEEP e WAKEUP Problema: Se o buffer estiver vazio e o consumidor sofrer preempção antes de dormir o produtor produz e envia um wakeup para o consumidor que ainda não está dormindo o sinal se perde e o consumidor dormirá para sempre... 15 Comunicação e Sincronização 8