Threads – Parte 1 (Conceitual)
Quando utilizamos nossos computadores, independente de quantos núcleos seu processador possua, temos a sensação de que o sistema operacional e todos os aplicativos são executados ao mesmo tempo, mas isto não é uma verdade.
Nosso computador trabalha na verdade com uma lista de processos, cada um desses processos pode utilizar o processador durante um pequeno espaço de tempo. O tempo e a freqüência em que os processos podem utilizar os recursos são baseados em uma série de fatores, dentre eles a prioridade.
Então, como temos a sensação de que tudo “acontece ao mesmo tempo”? Porque a tecnologia de processadores evoluiu muito e, hoje, temos processadores poderosos que executam uma grande quantidade de tarefas por milésimo de segundo.
É verdade que com o advento dos processadores de mais de um núcleo, mais processos podem ser executados ao mesmo tempo, um processador com dois núcleos pode executar dois processos ao mesmo tempo, quatro núcleos executam quatro processos, etc. Mas ainda sim o que manda é a velocidade em que as tarefas são executadas.
Como nós, meros desenvolvedores, podemos fazer para que nossas aplicações façam um bom uso desse precioso tempo que será concedido á ela na lista de processos do sistema operacional???
A resposta é: Desenvolvendo aplicativos Multi-Thread.
Mas, o que é uma Thread?
Uma Thread é uma espécie de “sub-processo” dentro do processo principal. Quando o processo do seu aplicativo for eleito para utilizar os recursos de processamento, ele poderá dividir esse tempo entre várias tarefas internas.
Exemplificando a coisa:
Necessidade: Gravar um arquivo em disco e enviar um comando para a porta serial, e se ambos derem certo, disparar um e-mail.
Cenário 1 (Aplicação Single-Thread):

É executado um sub-processo por vez, e um após o outro. Primeiro é gravado o arquivo em disco, depois é feita a comunicação com a porta serial e por fim é disparado o email.
Cenário 2 (Aplicação Multi-Thread):

Os dois primeiros processos são executados em Threads separadas, concorrentemente, e ao fim das duas Threads, o email é disparado, isso resulta num ganho de tempo, pois acessar o disco e enviar um comando para a porta serial são processos que levam tempo e podem ser executados de forma independente.
Porque Utilizar Thread
- Aumentar o número de atividades executadas por unidade de tempo.
- Esconder a latência do tempo de resposta (no exemplo: Gravar Arquivo em Disco, ou Enviar Comando para a Porta Serial)
Tipos de Thread
Threads podem ser implementadas em dois níveis diferentes: “User Level Threads” e “Kernel Level Threads”. Falando em aplicações escritas em .Net ou em Java, estaremos criando “User Level Threads” ou Threads em nível de usuário.
Threads em Nível de Usuário:
- Todo o gerenciamento das threads é feito a nível de aplicação.
- Threads são implementadas por uma biblioteca ligada ao programa
- Interface de programação para funções de manipulação de Threads (criação, sincronismo, término, etc).
- O núcleo do sistema não sabe da existência das Threads.
- A troca de mensagens entre as Threads é feita pelo escalonador embutido na biblioteca.
- Possuem comunicação por memória compartilhada.
Vantagens:
- O Sistema Operacional divide o tempo de processador entre os processos e, a biblioteca de threads divide o tempo entre as threads.
- Sem intervenção do Sistema Operacional.
Desvantagens:
- Não explora o paralelismo das maquinas multi-processadas.
Threads em nível de Sistema
- O núcleo do sistema sabe da existência das Threads.
- O S.O. mantém informações sobre processos e sobre Threads.
- Troca de contexto necessita a intervenção do S.O.
Vantagens:
- Explora o paralelismo das maquinas multi-processadas.
Desvantagens:
- Implementação mais complexa.
- As Threads não possuem comunicação por memória compartilhada.
- Sem interface de programação para manipular Threads, devem ser feitas solicitações para o S. O.
Legal, mas… e daí?
Bom, é legal sabermos que existem as Treads em nível de sistema, mas em nosso dia-a-dia iremos utilizar as Threads em nível de usuário, até porque plataformas como .Net e Java possuem bibliotecas que encapsulam a complexidade para manipulação deste tipo de Threads.
Quando Utilizar Threads
Para ter um melhor desempenho com Threads, um programa deve ser organizado em tarefas independentes que possam ser executadas de maneira concorrente. Por exemplo, se tivermos procedimentos que podem ser trocados de ordem ou intercalados, então são procedimentos que podem ser invocados por threads separadas.
Tarefas com possibilidade de serem executadas por Threads separadas
- Com possibilidade de ficarem bloqueadas por um tempo longo.
- Usam muitos ciclos de CPU.
- Que respondam a eventos assíncronos.
- Que são aptas á serem executadas em paralelo com outras tarefas.
Como Criar Threads
Em .Net: O Framework .Net possui o namespace “System.Threading” que provê todas as classes necessárias para manipular Threads. (Irei abordar este item no próximo post: Threads – Parte 2 (.Net))
Em Java: A JVM (Java Virtual Machine) possui o pacote “Java.lang.Thread” e ele também provê todas as classes necessárias para manipular Threads. (Este é tema de outro capítulo deste post: Threads – Parte 3 (Java))
Até o próximo Post…
Sergio.
Referências:
http://www.de9.ime.eb.br/~ishikawa/pg/ProgConc/threads.ppt
http://www.ucb.br/prg/professores/gualeve/disciplinas/2006_1/sobsi/02_Processos.pdf
