8 – Threads

Propaganda
1
8 – Threads
8.1 – Introdução
Uma thread, também chamada de tarefa, pode ser definida como uma
parte ou rotina de um processo em execução que compartilha o mesmo espaço
de endereçamento, mas tem seu próprio contexto de hardware e de software.
Um processo pode ter várias threads, podendo estas tarefas serem executadas
em paralelo.
Até o final da década de 1970, os sistemas operacionais suportavam
apenas processos com um único thread (monothread), ou seja, um processo
com um único programa fazendo parte do seu contexto. Em 1979, foi
introduzido o conceito de processo lightweight (peso leve), onde o espaço de
endereçamento de um processo é compartilhado por vários programas.
A partir do conceito de múltiplos threads (multithread), um processo
pode ter diferentes partes do seu código sendo executado em paralelo. Como
os threads de um mesmo processo compartilham o mesmo espaço de
endereçamento, a comunicação entre os threads é mais rápida, visto que não
envolve os mecanismos de comunicação entre processos.
Atualmente, o conceito de multithread pode ser encontrado em diversos
sistemas operacionais, entre eles o Microsoft Windows, Linux, Mac OS e o
Solaris, da Sun Microsystems.
8.2 – Ambiente Monothread
Um ambiente monothread suporta apenas um programa no seu espaço
de endereçamento. Neste tipo de ambiente, aplicações concorrentes são
implementadas apenas com o uso de múltiplos processos independentes ou
subprocessos.
Com o uso de múltiplos processos, cada funcionalidade do software
implicaria na criação de um novo processo para atender a essa funcionalidade.
2
Outro problema é quanto ao compartilhamento do espaço de endereçamento.
Como cada processo possui o próprio espaço de endereçamento isto
comprometeria o desempenho da aplicação.
8.3 – Ambiente Multithread
Em um ambiente multithread, não existe a ideia de programas
associados a processos e sim a threads. O processo neste tipo de ambiente
tem pelo menos uma thread em execução, mas pode compartilhar o espaço de
endereçamento com outros inúmeros threads.
Uma thread pode ser definida como uma sub-rotina de um programa que
pode ser executada de forma assíncrona, ou seja, executada paralelamente ao
programa. Um ambiente multithread possibilita a execução concorrente de subrotinas dentro de um mesmo processo. A grande vantagem do uso de threads
é a possibilidade de minimizar a alocação de recursos do sistema, além de
diminuir o overhead na criação, troca e eliminação de processos.
Threads compartilham o processador da mesma maneira que os
processos e passam pelas mesmas mudanças de estado. Dentro de um
mesmo processo, threads compartilham o mesmo espaço de endereçamento,
mas cada thread possui seu próprio contexto de hardware e contexto de
software.
Threads são implementados por uma estrutura de dados chamada
Bloco de Controle de Thread(Thread Control Block – TCB). Esta estrutura
armazena o contexto de hardware do thread e mais algumas informações como
prioridade e estado de execução.
Em um ambiente multithread, a unidade de alocação de recursos é o
processo,
onde
todos
os
seus
threads
compartilham
o espaço
de
endereçamento. Por outro lado, cada thread representa uma unidade de
escalonamento, sendo assim, o sistema não seleciona o processo para ser
executado, mas sim uma de suas threads.
A grande diferença de aplicações monothreads e multithreads está no
uso do espaço de endereçamento. Como os threads de um mesmo processo
compartilham o mesmo espaço de endereçamento, não existe qualquer
3
proteção no acesso à memória, permitindo que um thread possa alterar
facilmente os dados de outros e vice-versa.
Programa concorrentes com múltiplos threads são mais rápidos que
programas concorrentes implementados com múltiplos processos. Como os
threads de um mesmo processo dividem o mesmo espaço de endereçamento,
a comunicação entre eles é realizada de forma mais rápida e eficiente.
Tabela 8.1 - Comparação entre Processo e Threads
A utilização dos recursos do sistema computacional pode ser feita de
forma concorrente pelos diversos threads, por exemplo, enquanto algumas
aplicações realizam algumas tarefas em background, outras threads vão
realizando operações de Entrada/Saída.
8.4 – Arquitetura e Implementação
As threads podem ser oferecidas por meio de uma biblioteca de rotinas
fora do kernel do sistema operacional (modo usuário), pelo próprio kernel
(modo kernel), pela combinação dos dois modos (modo híbrido) ou por um
modelo conhecido como scheduler activations ou ativações do escalonador.
8.4.1 – Threads em Modo Usuário
Threads em modo usuário são implementadas pela própria aplicação e
não pelo sistema operacional. Para isso, deve existir uma biblioteca que
permita à aplicação realizar tarefas como a criação/eliminação de threads,
troca de mensagens, escalonamento, etc. Neste modo o sistema operacional
não sabe da existência dos threads, sendo a aplicação a única responsável por
gerenciar essas threads.
4
Figura 8.1 – Threads em modo usuário
Uma vantagem deste modo é a rapidez e eficiência, pois o sistema
operacional não sabe da existência das threads, isso evita a mudança do modo
de acesso. Uma desvantagem é que o sistema operacional gerencia cada
processo como se o mesmo tivesse apenas uma única thread. Quando o
processo em estado de execução vai para o estado de espera, todas as suas
threads também são colocadas em estado de espera, mesmo estando no
estado de pronto. Neste caso, é preciso criar rotinas que permitam a essas
threads serem executadas. Esse controle é transparente para o usuário e para
o sistema operacional.
Um dos maiores problemas na implementação de threads em modo
usuário é o tratamento individual de sinais. Como o sistema operacional
reconhece apenas os processos e não threads, os sinais são enviados para o
processo, que devem ser reconhecidos e encaminhados a thread responsável
para o devido tratamento.
8.4.2 – Threads em Modo Kernel
Threads em modo kernel são implementados diretamente pelo núcleo do
sistema operacional, através de chamadas a rotinas do sistema que oferecem
todas as funções de gerenciamento. Neste modo, o sistema operacional sabe
da existência de cada thread e pode escaloná-los individualmente.
5
Figura 8.2 – Threads em modo kernel
O grande problema deste modo é que threads em modo kernel utilizam
system calls e, consequentemente, há várias mudanças de modo de acesso,
enquanto que as threads em modo usuário fazem todo o tratamento sem a
intervenção do sistema operacional.
8.4.3 – Threads em Modo Híbrido
A arquitetura de threads em modo híbrido combina as vantagens de
threads implementados em modo usuário com as dos threads em modo kernel.
Um processo pode ter vários Threads em Modo Kernel e, este, por sua vez, ter
vários threads em modo usuário. O núcleo do sistema operacional reconhece
os threads em modo kernel e pode escaloná-los individualmente. Um thread
em modo usuário pode ser executado por em thread em modo kernel em um
determinado momento, e no instante seguinte, ser executado em outro.
6
Figura 8.3 – Threads em modo híbdrido
O modo híbrido é mais flexível, pois implementa os dois modos em
conjunto, mas também herda os problemas provenientes de ambos. Quando
um thread em modo kernel realiza uma chamada bloqueante, todos os threads
em modo usuário são colocados no estado de espera. Threads que utilizam
vários processadores devem utilizar diferentes threads em modo kernel, uma
para cada processador, o que influi no desempenho.
8.4.4 – Scheduler Activations (Ativações do Escalonador)
O modelo ideal de implementação de threads deveria unir e utilizar as
facilidades das threads em modo kernel com o desempenho e flexibilidade do
modo usuário. Nesta arquitetura, ao invés de dividir as threads em modo
usuário e modo kernel, como é feito no modelo híbrido, o kernel do sistema
operacional troca informações com a biblioteca de threads utilizando uma
estrutura de dados chamada scheduler activation.
7
Figura 8.4 – Scheduler Activations
A maneira de alcançar um melhor desempenho é evitar as mudanças de
modos de acesso. Caso uma thread utilize uma chamada ao sistema que a
coloque em estado de espera, a própria biblioteca em modo usuário escalona
outra thread.
8.5 – Modelos de Programação
Um fator importante é a forma como as threads são criadas e
eliminadas. Se uma aplicação cria um número excessivo de threads, poderá
ocorrer uma sobrecarga no sistema, ocasionando uma queda de desempenho.
Dependendo da aplicação, a definição do número de threads pode ser
dinâmica ou estática. Quando a criação/eliminação é dinâmica, os threads são
criados/eliminados de acordo com a demanda da aplicação, permitindo assim
uma maior flexibilidade. Já em ambientes estáticos, o número de threads é
definido na criação do processo onde a aplicação será executada.
Para obter os benefícios do uso de threads, uma aplicação deve permitir
que partes diferentes de seu código sejam executados em paralelo, de forma
independente. Sistemas gerenciadores de banco de dados (SGBD), servidores
de aplicações, servidores de arquivos ou impressão são exemplos onde o uso
de múltiplos threads proporciona vantagens e benefícios.
Download