Sincronização de Threads
Curso:
Engenharia de Controle e Automação
Disciplina:
Disciplina:
Informática Aplicada II
Professor:
Sincronização de Threads
Contextualização
o
Funcionamento
• Linha de execução (em inglês: Thread), é uma forma de um processo dividir a si
mesmo em duas ou mais tarefas que podem ser executadas concorrentemente
• O suporte à thread é fornecido pelo próprio sistema operacional (SO), no caso
da linha de execução ao nível do núcleo Kernel-Level Thread (KLT), ou
implementada através de uma biblioteca de uma determinada linguagem, no caso de uma User-Level Thread (ULT).
Sincronização de Threads
Contextualização
o
Um exemplo simples pode ser expressado através de um jogo onde o
mesmo pode ser modelado com linhas de execução diferentes, sendo uma
para desenho de imagem e outra para áudio
o
Neste caso, há um thread para tratar rotinas de desenho e outro thread
para tratar áudio
para tratar áudio
o
No ponto de vista do usuário, a imagem é desenhada ao mesmo tempo em
que o áudio é emitido pelos auto-falantes
o
Porém, para sistemas com uma única CPU, cada linha de execução é
Sincronização de Threads
Contextualização
o
Particularidades
• Cada linha de execução tem o mesmo contexto de software e compartilha o
mesmo espaço de memória (endereçado a um mesmo processo pai), porém o contexto de hardware é diferente
• Sendo assim o overhead causado pelo escalonamento de linha de execução é
muito menor do que o escalonamento de processos, entretanto, não há acesso protegido a memória nativamente (sua implementação fica a cargo do
programador) devido ao compartilhamento do espaço de memória
• Um benefício do uso das linhas de execução advém do fato do processo poder
ser dividido em mais de uma linha de tarefas; quando uma linha está esperando determinado dispositivo de entrada/saída ou qualquer outro recurso do sistema, o processo como um todo não fica parado, pois quando uma linha de execução entra no estado de bloqueio uma outra thread aguarda na fila de prontos para executar
Sincronização de Threads
Contextualização
o
Particularidades
• Uma linha de execução possui um conjunto de comportamentos padrão,
normalmente encontrados em qualquer implementação ou sistema operacional. Uma linha de execução pode:
criar outra da mesma forma que um processo, tal advento é conhecido como thread-create, onde a thread retorna um ID ao primeiro como primeiro argumento, como resultado da função de criação
esperar outra para se "juntar" (sincronizar), tal advento é conhecido como join
voluntariamente "desistir" da CPU, por não ser preciso mais o processamento proposto por ela ou pela vontade do usuário, tal advento é conhecido como thread-yield
replicar-se sem a necessidade de duplicar todo o processo, economizando assim memória, processamento da CPU e aproveitando o contexto (variáveis, descritores, dispositivos de I/O)
Sincronização de Threads
Contextualização
o
ULT e KLT
• Usualmente as linhas de execução são divididas em duas categorias:
linha de execução ao nível do usuário (User-Level Thread - ULT) linha de execução ao nível do núcleo (Kernel-Level Thread - KLT)
• As linhas de execução da primeira categoria são suportadas pela aplicação,
sem conhecimento do núcleo e geralmente são implementadas por pacotes de rotinas fornecidas por uma determinada biblioteca de uma linguagem
• Estas linhas de execução suportam as mesmas operações que as linha de
execução KLT
São quatro operações básicas do gerenciamento de linha de execução: criação, término, Junção e Rendimento
Sincronização de Threads
Contextualização
o
ULT e KLT
• Criação (thread creation)
Basicamente uma linha de execução pode dividir uma linha de execução em duas,
depois estas linhas(threads) executam simultaneamente, a thread criadora é a thread pai e a thread criada é a thread filho
Threads incluídas na função main quando executadas pode criar threads filho, por
Threads incluídas na função main quando executadas pode criar threads filho, por
exemplo:
Um thread A é executa inicialmente, mais tarde é criada o thread B. Depois de criadas, o thread A e thread B executam simultaneamente. Em seguida o thread A pode criar um ou mais threads (thread C). Depois de criada o thread C, há três threads executando
simultaneamente e todos disputam o uso da CPU. Entretanto, o thread que pode ser executada a qualquer momento não é de conhecimento da CPU
Sincronização de Threads
Contextualização
o
ULT e KLT
• Término (thread termination)
Para maioria dos casos os threads não são criados e executadas eternamente.
Depois de terminado seu trabalho, o thread termina
O thread que criou esses dois threads filho terminam também porque sua tarefa atribuída se completa
atribuída se completa
Se o thread pai terminar, todas as threads filho terminam também. Porque isso é importante?
Isso é importante porque os threads filho compartilham recursos com o thread pai, incluindo variáveis. Quando o thread pai termina, todas as variáveis são perdidas e o thread filho não poderá acessar os recursos que a thread pai possui. Assim, se o thread pai termina mais cedo que o thread filho haverá um problema
Sincronização de Threads
Contextualização
o
ULT e KLT
• Junção (Thread Join)
Imagine a seguinte situação
Você está estudando para uma prova. Então você pede o seu irmão mais novo para comprar uma pizza. Neste caso você é o thread principal e seu irmão o thread filho. Uma vez que você deu a ordem você e seu irmão começam a “executar uma tarefa” simultaneamente. Agora há deu a ordem você e seu irmão começam a “executar uma tarefa” simultaneamente. Agora há dois casos a se considerar. Primeiro, seu irmão traz a pizza e termina enquanto você estuda. Nesse caso você pode parar de estudar e comer a pizza. Segundo, Você acaba de estudar mais cedo e dorme e depois a pizza chegará
A junção de threads (thread join) é destinada para resolver este problema. O thread
pode executar o join e aguardar até o outro thread terminar
No caso acima você é o thread principal e deve executar o join aguardando o seu irmão terminar
Sincronização de Threads
Contextualização
o
ULT e KLT
• Thread Yield (Rendimento da thread)
Suponha que você executa um certo número de programas o tempo todo no
computador. Isso pode ser um problema de política de planejamento do sistema operacional
Quando nós escrevemos nossos programas com múltiplas threads, temos que tomar
Quando nós escrevemos nossos programas com múltiplas threads, temos que tomar
certos cuidados para que alguns threads não ocupem a CPU eternamente, ou por um tempo muito longo sem abandoná-lo
Liberamos espaço na memória graças a thread yield. Quando o thread executa o yield, a execução do thread é suspensa e a CPU passa para um outro thread em execução
Sincronização de Threads
Exemplos
o
Execute e analise o programa
ExemploJuncao.java
oExecute e analise o programa
ExemploPrioridade.java
Sincronização de Threads
Introdução a sincronização
o
Por enquanto, os threads que vimos são independentes
• Os threads não requerem acesso a recursos externos ou a chamdas de
métodos de outros objetos
• Os threads não precisam de preocupar com o que está ocorrendo com os
outros threads
o
Em outras situação, threads devem compartilhar dados e são obrigados a
Sincronização de Threads
Introdução a sincronização
o
Um exemplo disso é a aplicação chamada "Produtor/Consumidor" em que
um Produtor produz um fluxo de dados consumidos pelo consumidor
• Por exemplo, um thread (o produtor) poderia estar gravando dados num arquivo
enquanto outro thread (o consumidor) lê dados do mesmo arquivo
• Outro exemplo: enquanto você digita no teclado, o produtor coloca eventos de • Outro exemplo: enquanto você digita no teclado, o produtor coloca eventos de
mouse numa fila de eventos e o consumidor lê os eventos da mesma fila
• Em ambos os casos, temos threads que compartilham um recurso comum • Com tal compartilhamento, os threads devem se sincronizar para acessar o
Sincronização de Threads
Introdução a sincronização
o
Chamado de Produtor e o Consumidor (também conhecido como o
problema do buffer limitado), consiste em um conjunto de processos que
compartilham um mesmo buffer
• Os processos chamados produtores põem informação no buffer
• Os processos chamados consumidores retiram informação deste buffer • Os processos chamados consumidores retiram informação deste buffer
o
Esse é um problema clássico em sistemas operacionais, que busca
exemplificar de forma clara, situações de impasses que ocorrem no
gerenciamento de processos de um sistema operacional
Sincronização de Threads
Sincronização de Threads
o
Material de referencia
Sincronização de Threads
Atividade
o