Escolar Documentos
Profissional Documentos
Cultura Documentos
Abstract. This article aims to describe the operation of code that detects and
reports deadlocks in a system. The points covered in this article are: The
methodology of creating the source code and the computational tests made in
the source code. This article is made for the discipline of Operating Systems of
the bachelor's degree in Computer Science, taught by professor Reginaldo
Santos.
Resumo. Este artigo tem como objetivo descrever o funcionamento de um
código que detecta e reporta impasses em um sistema. Os pontos abordados
neste artigo são: A metodologia da criação do código-fonte e os testes
computacionais feitos no código fonte. Este artigo é feito para a disciplina de
Sistemas Operacionais do curso de bacharelado em Ciência da Computação,
ministrado pelo docente Reginaldo Santos.
1. Introdução
Em um sistema operacional, há vários processos sendo criados e mortos a todo instante,
muitos desses processos precisam de recursos geridos pelo próprio sistema operacional
para poderem concluir suas funções. Por vezes, espera-se que ocorram impasses
(deadlocks) que obstruam o funcionamento correto dos processos causados pela falta de
recursos disponíveis.
Segundo Tanenbaum, impasse pode ser definido como: “Um conjunto de
processos estará em situação de deadlock se todo processo pertencente ao conjunto estiver
esperando por um evento que somente um outro processo desse mesmo conjunto poderá
fazer acontecer”.
Uma forma mais simples de explicar seria com o exemplo de um cruzamento de
transito, onde um carro na via A pede passagem a um carro na via B, mas o pedido é
negado, e o carro na via B pede passagem para o carro na via C, mas o pedido também é
negado, o mesmo ocorre com o carro na via C para o da via D, e por fim o carro na via D
pede passagem pro carro na via A, que não tem como passar e nega o pedido, assim,
nenhum dos carros pode prosseguir seu caminhos, pois a outros esperando as vias serem
livres. Isso configura um impasse.
Como foi dito anteriormente, um impasse pode ocorrer naturalmente em um
sistema operacional, porém, é necessário que se cumpram 4 condições para que eles
apareçam:
Condição de exclusão mutua: em um determinado instante, todo recurso está
alocado para um único processo ou está livre.
Condição de posse e espera: um processo que já tem recursos alocados para si,
pede por mais recursos.
Condição de não preempção: Um recurso alocado à um processo não pode ser
tomado a força.
Condição de espera circular: Uma cadeia circular de espera se forma entre um ou
mais processos, onde um espera a liberação de recursos alocados em outro e assim
sucessivamente.
Para que ocorra um impasse, todas as condições acima citadas têm que ocorrer ao
mesmo tempo.
Para a melhor compreensão de um impasse, eles também podem ser representados
por um grafo, onde o recurso por um círculo e o processo é representado por um quadrado.
Quando um processo solicita um recurso, uma seta é dirigida do quadrado ao círculo.
Quando um recurso é alocado a um processo, uma seta é dirigida do círculo ao quadrado,
como mostrado na figura abaixo:
3. Recursos Computacionais
Para este artigo foram utilizados os seguintes recursos: Sistema Operacional Windows 11,
Sistema Operacional Linux Ubuntu 20.04, a escolha desses sistemas operacionais foi feita
mediante a porcentagem de utilização deles pelo público geral.
A linguagem de programação utilizada foi Python versão 3.8.12, a escolha da
linguagem de programação foi baseada nos recursos já oferecidos por essa que
facilitariam o processo de escrita do código, os principais utensílios que auxiliaram na
construção do código foram os recursos de biblioteca da linguagem.
A principal biblioteca utilizada foi a biblioteca Pickle, cuja função assumida foi a
de formatação e decodificação de arquivos .pkl para a transposição das informações
desses para a execução dos testes descritos em cada cenário.
A IDE utilizada foi o site de IDE online repl.it, que foi escolhido por ser uma
ótima plataforma de codificação em conjunto, onde cada participante pode dar sua
contribuição para o código ao mesmo tempo.
4. Testes Computacionais
Para os testes computacionais foram desenvolvidos 6 cenários distintos, usados como
base da entrada de dados do algoritmo de análise de impasses. Foi desenvolvido um
algoritmo de detecção de impasses que tem como entrada a matriz de requisição R, a
matriz de alocação atual C e o vetor de recursos disponíveis A. Utilizando a comparação
entre as diferentes matrizes e vetores inseridos na entrada, o algoritmo verifica cada
processo e seus recursos requisitados a fim de verificar se é possível fazer essa requisição.
Se for possível, ele aloca, considera que o processo foi terminado e libera os recursos
atualmente alocados. Caso não seja possível, ele não faz alteração alguma nas matrizes e
vetores. O algoritmo é repetido até que não haja mais mudança nos recursos alocados no
processo. Isso sinaliza que ou todos os processos foram concluídos, ou que houve um
impasse entre eles. Para os testes computacionais, foram utilizados arquivos de extensão
.pkl, que foram decodificados em dicionários que, por sua vez, foram convertidos em
diferentes matrizes e vetores para servirem de entrada para o algoritmo. Na criação desses
arquivos codificados em .pkl, foi desenvolvido um outro algoritmo que, usando como
base o primeiro já citado, gera as duas matrizes e os dois vetores aleatoriamente usando
como base o número de processos, número de recursos e a quantidade de impasses
desejados para determinado cenário. Os dados das matrizes e vetores dos cenários serão
descritos a seguir:
4.1. Cenário 1
Para o primeiro cenário, forma usados os seguintes valores:
A matriz de requisição R é:
4.2. Cenário 2
Para o segundo cenário, foram usados os seguintes valores:
A matriz de requisição R é o seguinte:
4.3. Cenário 3
Para o terceiro cenário, foram usados os seguintes valores:
A matriz de requisição R é o seguinte:
4.4. Cenário 4
Para o quarto cenário, foram usados os seguintes valores:
A matriz de requisição R é o seguinte:
4.5. Cenário 5
Para o quinto cenário, foram usados os seguintes valores:
A matriz de requisição R é o seguinte:
5. Conclusão
Um impasse ocorre em um sistema operacional, casualmente, e depende da
complexidade do mesmo. Um bom método de evitar problemas em tempo de execução,
é detectar esses impasses e tentar resolve-los, sem muito prejuízos para o sistema. Um
algoritmo de detecção de impasses se faz extremamente necessário em casos assim, pois
apenas com a análise de matrizes e vetores que representam os recursos e processos no
cenário do sistema operacional, é possível saber se aquela ação resultará em um impasse
ou não, assim, tornando mais fácil saber qual decisão o sistema operacional deverá tomar.
Com a análise dos dados obtidos do processamento do algoritmo de detecção de
impasses, pode-se concluir que em cada cenário o algoritmo cumpre seu papel de avisar
ao sistema sobre possiveis impasses perfeitamente, podendo ser utilizado em um sistema
operacional sem nenhum tipo de problema.
6. Referencias
Tanenbaum, Andrew S. (2016) “Sistemas Operacionais Modernos”, 4. ed - São Paulo
Anexo 1 – Código do Algoritmo detector de impasses
import pickle
if __name__ == '__main__':
with open(r'cenario3.pkl', 'rb') as file:
cenario = pickle.load(file)
# Atribuindo os devidos valores do cenário escolhido
A = cenario['A']
E = cenario['E']
C = cenario['C']
R = cenario['R']
print(f'A: {A}')
print(f'E: {E}')
print(f'C: {C}')
print(f'R: {R}')
print('\n\n')
a0 = None
a1 = None
if a0 == a1:
break
a0 = a1
i = 0
else:
print("Não há impasses no sistema.")
Figura 26. algoritmo_detector.py
Anexo 2 – Algoritmo Gerador de Impasses
from random import randint
import copy
from algoritmo_detector import checar_recursos
# Faz uma deep copy do vetor A para que ele não seja modi-
ficado antes
# de se ter certeza de que o procedimento dará certo
vetor_a_backup = copy.deepcopy(vetor_a)
linha_processo = []
# Esse loop irá continuar até que se forme uma matriz requisição R
que atenda ao número de
# impasses passado como parâmetro na função
while True:
matriz_r = []
vetor_checagem = []
for i in range(0, n_processos):
vetor_checagem.append(0)
# Faz uma deep copy dos dados que entrarão na função che-
car_recursos.
matriz_rcopia = copy.deepcopy(matriz_r)
a_copia = copy.deepcopy(vetor_a)
c_copia = copy.deepcopy(matriz_c)
if __name__ == '__main__':
# Testa a função.
print(impasse_generator(4, 5, 2))
Figura 27. impasse_generator.py