<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>PauloMotta.pro &#187; CONCORRÊNCIA</title>
	<atom:link href="http://www.paulomotta.pro.br/tag/concorrencia/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.paulomotta.pro.br</link>
	<description>&#34;Qualquer tecnologia suficientemente avançada é indistinguível da mágica&#34; - Arthur C. Clarke</description>
	<lastBuildDate>Tue, 10 Jan 2012 03:00:16 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.2</generator>
		<item>
		<title>Exclusão Mútua, Semáforos e Monitores</title>
		<link>http://www.paulomotta.pro.br/2009/08/25/exclusao-mutua-semaforos-e-monitores/</link>
		<comments>http://www.paulomotta.pro.br/2009/08/25/exclusao-mutua-semaforos-e-monitores/#comments</comments>
		<pubDate>Tue, 25 Aug 2009 20:30:33 +0000</pubDate>
		<dc:creator>prmottajr</dc:creator>
				<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Principal]]></category>
		<category><![CDATA[CONCORRÊNCIA]]></category>
		<category><![CDATA[DISTRIBUIÇÃO]]></category>
		<category><![CDATA[PARALELISMO]]></category>
		<category><![CDATA[PROGRAMAÇÃO]]></category>

		<guid isPermaLink="false">http://www.paulomotta.pro.br/2009/08/25/exclusao-mutua-semaforos-e-monitores/</guid>
		<description><![CDATA[Os computadores com mais de um processador chegaram para ficar. Existem pesquisas no sentido de substituir o silício usado para construir os processadores por outra substância, mas enquanto isso não se torna economicamente viável a saída para o silício, uma vez que chegamos ao limite de velocidade que podemos atingir, a alternativa é aumentar a [...]]]></description>
			<content:encoded><![CDATA[<p><!-- p { margin-bottom: 2.12mm; } -->Os computadores com mais de um processador chegaram para ficar. Existem pesquisas no sentido de substituir o silício usado para construir os processadores por outra substância, mas enquanto isso não se torna economicamente viável a saída para o silício, uma vez que chegamos ao limite de velocidade que podemos atingir, a alternativa é aumentar a quantidade de núcleos executando. Isso significa na prática que agora o sistema operacional pode colocar mais de um programa efetivamente executando ao mesmo tempo. Embora possam executar ao mesmo tempo porque haverá mais de um processador, as aplicações vão concorrer pelos outros recursos, porque de acordo com nossas arquiteturas baseadas no modelo von Neuman, usamos um barramento para fazer as trocas de informações e para acessar canais de entrada e saída.</p>
<p>Essa característica já é estudada nos cursos de sistemas operacionais há tempos, até porque quando só havia um núcleo disponível (e isso ainda acontece em diversas plataformas) as aplicações concorrem também pelo uso do processador. A parte interessante é que este problema, típico da área de sistemas, foi trazido para a área de aplicações inicialmente quando tivemos acesso à criação de novos processos (via fork por exemplo) e à threads. Neste último caso, as novas linguagens já trazem suporte ao trabalho com threads de forma nativa o que ajudou muito a difundir seu uso, no entanto talvez não tenhamos dado devida atenção ao domínio das técnicas para usar esse tipo de ferramenta.</p>
<p>Existe muito material disponível sobre threads, mas por hora podemos entender como sendo as linhas de execução de um programa, ou seja, mais de uma tarefa <em>do próprio programa</em> acontece (ou tenta acontecer) ao mesmo tempo. Com isso temos que nos preocupar com os problemas de concorrência, originalmente da área de sistemas, dentro da nossa aplicação.</p>
<p>Para isso vale a pena rever os conceitos ensinados em sistemas operacionais referentes a:</p>
<ul>
<li>Condições de corrida (race 	conditions) &#8211; dois ou mais participantes (aplicações) disputam 	entre si por um recurso, ou seja, se assemelha a uma corrida por um 	troféu.</li>
<li>Regiões críticas (critical regions) &#8211; são as regiões ou 	seções do programa em que fazemos uso do recurso que é 	compartilhado, identificando essas partes do programa torna-se 	possível isolá-las de forma que possamos controlar o início e fim 	do uso de algum recurso compartilhado.</li>
</ul>
<p>Tendo relembrado desses conceitos a primeira coisa que temos a falar é da exclusão mútua, que significa que dois ou mais participantes excluem-se entre si, ou seja, só um pode acessar o recurso compartilhado por vez. O problema então é: <em>como</em> conseguir sinalizar isso? Para responder essa pergunta temos uma série de técnicas que foram propostas também para a área de sistemas operacionais, até porque são técnicas de mais baixo nível. O ideal é que o mecanismo ou estratégia de exclusão mútua seja fornecido pelo ambiente (ou pela linguagem, ou pela biblioteca) usado.</p>
<p>A primeira forma que pensamos é a espera ocupada (busy wait), onde o processo que está esperando gasta seus ciclos de processador sem fazer nada, basicamente equivale a fazer um laço (while ou for) onde testamos a condição para saber se já pode ser executado. Como o sistema operacional faz a troca de processos de tempos em tempos, eventualmente o processo que tem controle do recurso vai terminar de usar e liberar, e alguém da fila de espera vai ser colocado para executar. Quando essa nova troca acontece o laço encerra uma vez que a condição de recurso livre foi atingida. Esses turnos vão se alterando, o que percebemos é que essa estratégia desperdiça ciclos de processador sem realizar uma tarefa útil, logo só serve como exemplo. Em alguns casos de máquinas com vários processadores (ou vários núcleos) pode ser necessário usar essa técnica para sincronizar a leitura de registradores compartilhados ou para verificar se um outro núcleo já disponibilizou o conteúdo esperado, encontramos exemplos disso em vários dos manuais da IBM para programação do Cell Broadband Engine, processador que equipa o Playstation 3 da Sony.</p>
<p>Uma outra alternativa mais de baixo nível (especificamente no nível da máquina exatamente) é ter uma instrução capaz de testar uma variável (ou registrador) e <em>no mesmo ciclo</em> trocar seu valor. A ideia aqui é que se a variável não estiver com alguma das aplicações concorrentes então quem executou essa instrução consegue o recurso, se não estiver disponível então simplesmente retorna. Bom a questão aqui é como disponibilizar essa instrução para as linguagens de mais alto nível</p>
<p>Por outro lado se usarmos uma solução baseada no sistema operacional ao invés de uma instrução de máquina, torna-se mais simples de torná-la acessível para as linguagens de programação de alto nível A alternativa é usar duas chamadas do sistema SLEEP (dormir) e WAKEUP (acordar), dessa forma quando testamos a variável e verificamos que a condição que precisamos não está disponível, executamos a chamada SLEEP para que o processo possa esperar até que o recurso esteja disponível De forma simétrica quando liberamos um recurso, chamamos WAKEUP dizendo qual processo deve executar agora (de forma que vá conseguir o recurso que tem interesse.)</p>
<p>Quando usamos semáforos, essas chamadas de sistema são encapsuladas em chamadas que realizam um controle extra. Isso é necessário porque as chamadas SLEEP e WAKEUP não conseguem por si só garantir a exclusão mútua. Um semáforo é uma variável especial sobre a qual podemos executar as operações DOWN (abaixar) e UP (levantar.) Como chamadas de sistemas, precisam ser implementadas com algum código, dentro desse código, além de verificar o valor da variável passada (o semáforo) também trocamos o valor se for o caso, como se fosse uma instrução de baixo nível Para garantir que o processo executando não vai ser interrompido antes da variável trocar o valor as interrupções da máquina são desligadas, isso garante a execução atômica, ou seja, como se fosse uma única instrução, logo em seguida as interrupções de máquinas são ligadas e o processo já pode ser trocado pelo sistema operacional.</p>
<p>Uma outra característica importante é que o uso de semáforos permite tornar a concorrência uma tarefa de mais alto nível já que elimina o uso de referências direta aos outros processos. Se for necessário um conjunto grande de processos executando o uso de semáforos permite conhecer apenas uma variável, enquanto a referência direta necessitaria de um vetor para armazenar todas as referências.</p>
<p>O problema surge quando usamos mais de um semáforo para controlar tanto a exclusão mútua quanto o uso do recurso compartilhado. Neste caso se não nos concentrarmos na ordem de execução das operações podemos acabar bloqueados</p>
<p>Uma solução para isso é o uso de monitores, que na verdade é uma construção mais ampla composta de funções e estruturas de dados próprias. Normalmente o compilador conhece essa estrutura e é <em>o compilador</em> que ordena as questões referentes as garantias de exclusão mútua e sincronização, isto porque um monitor é construído sobre as soluções oferecidas pelos semáforos. A vantagem disso é que o programador passa a usar um mecanismo de mais alto nível e só precisa conhecer as operações WAIT (esperar) e SIGNAL (sinalizar,) usadas sobre uma variável que <em>é</em> o monitor, ou seja, quando o programador declara a variável, o compilador intervem colocando as instruções necessárias para as garantias. Do ponto de vista conceitual, as soluções são bem parecidas, porém o programador trabalha de forma mais abstrata se preocupando em marcar as regiões que devem ser controlados pelo monitor. Quando o programa executa a instrução WAIT sobre um semáforo, este verifica se existe algum programa atualmente executando, se este for o caso, o novo programa entra em uma fila de espera controlado pelo monitor, caso contrário começa a executar. Quando um programa vai terminar sua seção crítica executa como sua última instrução um SIGNAL para o monitor, isso faz com que o programa <em>saia</em> do monitor e este escolhe um novo programa da fila para executar utilizando assim o recurso compartilhado. A estratégia de sincronia escolhida para a linguagem Java foi a de monitores, assim os mecanismos para seu uso são fornecidos como operações da própria linguagem e seu compilador se preocupa em colocar todos os controles necessários em seus devidos lugares.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.paulomotta.pro.br/2009/08/25/exclusao-mutua-semaforos-e-monitores/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

