Explicação

Sobre o Tema

O REA se trata de um simulador do problema do produtor/consumidor com sleep/wakeup tal como é apresentado no livro Modern Operating Systems (TANENBAUM, 2014, p. 129).

Este simulador tem como objetivo principal ilustrar a utilização e a semântica das primitivas sleep e wakeup, as quais podem ser primitivas de um sistema operacional para realização de comunicação entre processos (Interprocess Communication - IPC).

Mais especificamente, é ilustrada a utilização de tais primitivas para sincronização entre processos (e não para obtenção de exclusão mútua ou para transferência de dados, outros objetivos da IPC). De fato, a ausência de exclusão mútua nos códigos simulados são a fonte de uma race condition importante nesse cenário. Uma race condition, vale ressaltar, é um tipo de problema difícil de ser previsto, detectado, reproduzido e corrigido, advindo do acesso concorrente à memória compartilhada entre dois ou mais processos. Sua presença no cenário simulado motiva a introdução e o estudo dos semáforos, os quais podem ser usados para evitá-la.


Sobre o Cenário Simulado e as System Calls Sleep e Wakeup

O cenário do produtor/consumidor aqui tratado consiste em dois processos e um buffer de tamanho fixo compartilhado entre eles. A tarefa do processo produtor é criar itens e inserí-los no buffer, enquanto a do consumidor é removê-los deste (e realizar algum processamento em cima do item removido, algo aqui abstraído). Fica claro que não faz sentido o consumidor remover itens de um buffer vazio, e que o produtor não pode inserir itens num buffer cheio. É para fazer valer essa semântica que entram em cena as primitivas sleep e wakeup. Uma chamada a sleep faz com que um processo bloqueie ("durma"), para posteriormente ser acordado por outro processo realizando chamada a wakeup passando por parâmetro uma identificação (PID, o process identifier, por exemplo) do processo bloqueado.

A ideia para solução do problema, então, é que quando o processo produtor ou consumidor está impossibilitado de trabalhar (pois o buffer está cheio ou vazio, respectivamente), o mesmo bloqueia chamando sleep. O processo o qual permanecer "acordado" se encarrega então de "acordar" o processo bloqueado com chamada a wakeup assim que já estiver permitido que este continue a realizar sua tarefa - quando o buffer deixou de estar cheio ou vazio, respectivamente.


Sobre Race Conditions

Um usuário atento com algum conhecimento em Sistemas Operacionais e processos poderia perceber que o código da simulação parece apresentar problemas: o buffer e a variável count são compartilhados entre os dois processos e, portanto, o acesso aos mesmos constitui uma região crítica, região esta que pede exclusão mútua. O usuário com esse pensamento estaria absolutamente correto. Como dito acima, o par sleep/wakeup não está sendo empregado para obtenção de exclusão mútua. Não há nada que esteja protegendo o acesso concorrente aos elementos compartilhados. Race conditions podem ocorrer. A simulação representa isso fielmente, podendo ser utilizada para ilustrar tal conceito.

A race condition simulável mais importante (mas não a única) envolve o fato de que chamadas à wakeup para um processo que não esteja bloqueado são perdidas permanentemente. Isso pode em última instância fazer com que ambos produtor e consumidor fiquem bloqueados para sempre, como Tanenbaum explica no livro supracitado. Sugerimos que os usuários tentem, como exercício, alcançar essa situação por si mesmos.