Você está na página 1de 26

24 sistemas operacionais

Compartilhamento de recursos: a memria e os demais recursos do processo so


compartilhados pelos threads.
Economia: como a memria e os recursos so compartilhados, a sua alocao
acontece uma nica vez, na criao do processo.
Utilizao da arquitetura de multiprocessadores: em uma arquitetura de multiproces
sadores, cada thread pode ser executado em paralelo em um processador diferente.

Aprofundando o conhecimento
No texto a seguir, extrado do Captulo 4, Conceitos de threads, da terceira edio
do livro Sistemas operacionais, de Deitel, Deitel e Choffnes (2005, p. 90109), o autor
explica mais detalhadamente o que um thread e mostra o funcionamento dos thre
ads em diversos sistemas operacionais. Leia e aprofunde seu conhecimento.

4.2 Definio de thread


Devido ao amplo suporte para multithread em linguagens de programao,
praticamente todos os sistemas operacionais recentes fornecem, no mnimo,
algum suporte para threads. Um thread, s vezes denominado processo leve
(Lightweight Process LWP), compartilha muitos atributos de um processo.
Threads so escalonados em um processador, e cada thread pode executar um
conjunto de instrues independentemente de outros processos e threads. Entre
tanto, eles no so planejados para existir sozinhos normalmente pertencem a
processos tradicionais, s vezes denominados processos pesados (Heavyweight
Processes HWP). Os threads de um processo compartilham muitos dos seus
recursos mais notavelmente seu espao de endereamento e arquivos abertos
para melhorar a eficincia com que realizam suas tarefas. O nome thread
referese a um fluxo nico de instrues ou fluxo de controle; threads em um
processo podem executar concorrentemente e cooperar para atingir uma meta
comum. Em um sistema multiprocessador, mltiplos threads so capazes de exe
cutar simultaneamente.
Threads possuem um subconjunto dos recursos contidos em um processo.
Recursos como registradores de processador, a pilha e outros dados especficos
de threads (Thread-Specific Data TSD) tais como mscaras de sinal (dados que
descrevem quais sinais um thread no receber, discutidos na Seo 4.7.1, Entrega
de sinal de thread) so locais a cada thread, enquanto o espao de endereamento
pertence ao processo que contm os threads e global para os threads (Figura
4.1). Dependendo da implementao de thread para determinada plataforma,
os threads podem ser gerenciados pelo sistema operacional ou pela aplicao de
usurio que os cria.

Sistemas operacionais.indd 24 18.12.09 19:37:06


G e r n c i a d o p r o c e s s a d o r 25

Figura 4.1 Relacionamento entre thread e processo

Processo pesado

Informao global Espao de endereamento


para todos os
Outros dados globais de processo
threads de um
processo

Registradores Registradores Registradores

Pilha Pilha Pilha


Informao local
para cada thread
Mscara Mscara Mscara

TSD TSD TSD

Threads

Embora muitos sistemas operacionais suportem threads, as implementaes


variam consideravelmente. Threads Win 32,1 C-threads2 e threads POSIX3 so
exemplos de bibliotecas de suporte a threads com APIs dspares. Threads Win32
so usados nos sistemas operacionais Windows de 32 bits da Microsoft; C-threads
so criados por meio de uma biblioteca de suporte a threads no microncleo Mach
(sobre o qual construdo o Macintosh OS X) e tambm suportados pelos sistemas
operacionais Solaris e Windows NT. A especificao POSIX fornece o padro Pthre-
ads. O objetivo primordial dos Pthreads permitir a portabilidade de programas
multithread por meio de mltiplas plataformas de sistemas operacionais. O POSIX
foi implementado em uma variedade de sistemas operacionais, incluindo o Solaris,
o Linux e o Windows XP.

4.3 Motivao na criao de threads


Quando o conceito de processo foi introduzido pelo projeto Multics na d
cada de 1960, computadores continham, tipicamente, um nico processador, e
as aplicaes eram relativamente pequenas.4 Os processos daquela poca eram
projetados para executar um nico thread de controle em um processador por
vez. Tendncias subsequentes no projeto de software e hardware indicaram que
sistemas poderiam se beneficiar de mltiplos threads de execuo por processo.
Eis alguns fatores que motivaram o multithread:

Sistemas operacionais.indd 25 18.12.09 19:37:07


26 sistemas operacionais

Projeto de software Devido modularidade e ao projeto de compiladores,


muitas das aplicaes atuais contm segmentos de cdigo que podem ser
executados independentemente do restante da aplicao. Isolar segmentos de
cdigos independentes em threads individuais pode melhorar o desempenho
da aplicao e fazer com que fique mais simples exprimir tarefas inerentemente
paralelas em cdigo.
Desempenho Um problema das aplicaes monothread que atividades
independentes no podem ser escalonadas para executar em mltiplos pro
cessadores. Em uma aplicao multithread, os threads podem compartilhar
um processador (ou conjunto de processadores) para que vrias tarefas sejam
realizadas em paralelo. Execuo concorrente paralela pode reduzir significa
tivamente o tempo requerido para uma aplicao multithread concluir sua
tarefa, especialmente em sistemas multiprocessadores, em comparao com
uma aplicao monothread que pode executar somente em um processador
por vez e deve realizar suas operaes em sequncia. E mais, em processos
multithread, threads prontos podem executar enquanto outros esto bloquea
dos (isto , esperando concluso de E/S).
Cooperao Muitas aplicaes dependem de componentes independentes
para comunicar e sincronizar atividades. Antes dos threads, esses compo
nentes executavam como mltiplos processos pesados que estabeleciam
canais de comunicao interprocessos via ncleo.5, 6 O desempenho com
uma abordagem de mltiplos threads leves normalmente melhor do que
com uma abordagem de mltiplos processos pesados, porque os threads
de processo podem se comunicar usando seu espao de endereamento
compartilhado.

Hoje, aplicaes multithread so comuns nos sistemas de computadores. Um servi


dor Web um dos ambientes em que os threads podem melhorar extraordinariamente
o desempenho e a interatividade. Servidores Web tipicamente recebem requisies
de aplicaes remotas para pginas Web, imagens e outros arquivos. comum que
servidores Web atendam a cada requisio com um thread separado. O processo que
recebe requisies pode conter um thread que atende a requisies da Internet. Para
cada requisio recebida, gerado um novo thread que interpreta a requisio, recu
pera a pgina Web e a transmite ao cliente (tipicamente um navegador Web). Aps a
gerao de um novo thread, seu pai pode continuar a atender novas requisies. Como
muitos servidores Web so sistemas multiprocessadores, diversas requisies podem ser
recebidas e atendidas concorrentemente por diferentes threads, melhorando ambos, o
rendimento e o tempo de resposta. A sobrecarga incorrida pela criao e destruio de
um thread para atender a cada requisio substancial. Em consequncia, a maioria
dos servidores Web de hoje mantm um conjunto de threads destinados a atender a

Sistemas operacionais.indd 26 18.12.09 19:37:07


G e r n c i a d o p r o c e s s a d o r 27

novas requisies medida que elas chegam. Esses threads no so destrudos aps
atender requisio; ao contrrio, voltam ao conjunto e so novamente designados
para requisies que esto entrando.
Processadores de texto usam threads para aumentar a produtividade do usu
rio e melhorar a interatividade. Cada vez que o usurio digita um caractere no
teclado, o sistema operacional recebe uma interrupo de teclado e emite um sinal
para o processador de texto. Esse responde armazenando o caractere na memria
e exibindo-o na tela. Como os computadores atuais podem executar centenas
de milhes de instrues de processador entre digitaes sucessivas, processa
dores de texto podem executar diversos outros threads entre as interrupes do
teclado. Por exemplo, muitos dos processadores de hoje detectam erros de grafia
nas palavras medida que so digitadas e salvam periodicamente uma cpia do
documento para um disco para evitar perda de dados. Cada caracterstica imple
mentada com um thread separado consequentemente, o processador de texto
pode responder s interrupes do teclado mesmo que um ou mais de seus threads
estejam bloqueados devido a uma operao de E/S (por exemplo, salvar uma cpia
do arquivo em disco).

4.4 Estados de threads: ciclo de vida de um thread


Cada processo pode ser visto como transitando entre uma srie de estados
discretos de processo, como discutido anteriormente. Nesse modelo, cada processo
contm um nico thread de controle; portanto, poderamos ter dito tambm que
cada thread de controle passa por uma srie de estados discretos. Quando proces
sos contm mltiplos threads de controle podemos considerar cada thread como
transitando entre uma srie de estados de thread discretos. Assim, grande parte da
discusso dos estados de processo e de transies de estado aplica-se a estados e a
transies de estado de threads.
Por exemplo, considere o seguinte conjunto de estados baseado, em grande
parte, na implementao de threads no Java (Figura 4.2).7 Em Java, um novo thread
inicia seu ciclo de vida no estado nascido (born). Permanece no estado nascido at
que o programa inicie o thread, o que o coloca no estado pronto s vezes cha
mado de estado executvel (runnable). Em outros sistemas operacionais um thread
iniciado na sua criao, eliminando o estado nascido. O thread pronto de prioridade
mais alta entra no estado em execuo (comea a executar) quando obtm um
processador.
Um thread em execuo entra no estado morto (dead) quando conclui sua
tarefa ou termina de algum modo qualquer. Algumas bibliotecas de suporte a
threads permitem que um thread termine outro thread, o que fora esse ltimo a
passar para o estado morto. Uma vez que um thread entra no estado morto seus
recursos so liberados e ele removido do sistema.

Sistemas operacionais.indd 27 18.12.09 19:37:07


28 sistemas operacionais

Figura 4.2 Ciclo de vida do thread

nascido

Iniciar

pronto

em execuo

em espera adormecido morto bloqueado

Um thread entra no estado bloqueado quando deve esperar pela concluso


de uma requisio de E/S (ler dados de um disco). Um thread bloqueado no des
pachado para um processador at que sua requisio de E/S tenha sido concluda.
Nesse ponto, o thread retorna ao estado pronto, para que possa retomar a execuo
quando um processador estiver disponvel.
Quando um thread deve esperar por um evento (por exemplo, movimento do
mouse ou um sinal de outro thread), pode entrar no estado de espera. Uma vez
nesse estado, ele volta ao estado pronto quando um outro thread o notificar (o
termo acordar tambm usado). Quando um thread em espera recebe um evento
de notificao, ele transita do estado em espera para o estado pronto.
Um thread em execuo pode entrar no estado adormecido durante um
perodo de tempo especificado (denominado perodo de sono). Um thread adorme-
cido volta ao estado pronto quando seu intervalo designado de sono expira. Threads
adormecidos no podem usar um processador, mesmo que haja um disponvel.
Os threads adormecem quando no tm, momentaneamente, nenhum trabalho a
realizar. Por exemplo, um processador de texto pode conter um thread que grave

Sistemas operacionais.indd 28 18.12.09 19:37:12


Gerncia do processador 29

periodicamente uma cpia do documento corrente em disco para recuperao


posterior. Se o thread no dormisse entre backups sucessivos, exigiria um lao no
qual ele testasse continuamente se deve ou no gravar uma cpia do documento no
disco. Esse lao consumiria tempo de processador sem realizar trabalho produtivo,
reduzindo o desempenho do sistema. Nesse caso, mais eficiente que o thread
especifique um intervalo de sono (igual ao perodo entre backups sucessivos) e entre
no estado adormecido. O thread adormecido volta ao estado pronto quando seu
intervalo de sono expira, momento em que grava uma cpia do documento em
disco e retorna ao estado adormecido.

4.5 Operaes de thread


Threads e processos tm muitas operaes em comum, como:
criar;
sair (ou seja, terminar);
suspender;
retomar;
dormir;
acordar.

Sob muitos aspectos, a criao de threads semelhante criao de processos.


Quando um processo gera um thread, a biblioteca de suporte a threads inicia estruturas
de dados especficas de thread que armazenam informaes como contedo de regis
tradores, o contador do programa e um identificador de thread (ID). Diferentemente da
criao de processo, a de thread no requer que o sistema operacional inicialize recursos
compartilhados entre o processopai e seus threads (por exemplo, o espao de endere
amento). Muitos sistemas operacionais requerem um nmero menor de instrues para
compartilhar recursos do que para inicializlos, portanto, nesses sistemas, a criao de
thread mais rpida do que a de processo.8 Do mesmo modo, o trmino de um thread
geralmente mais rpido do que o de um processo. A reduo da sobrecarga decorrente
da criao e trmino de threads incentiva os desenvolvedores de software a implementar
tarefas paralelas usando mltiplos threads em vez de mltiplos processos quando isso
for possvel.
Algumas operaes de threads no correspondem exatamente s operaes de
processos, como as seguintes:
Cancelar Um thread ou processo pode fazer com que um thread termine
prematuramente, cancelandoo. Diferentemente do trmino de um processo,
o cancelamento de um thread no garante que ele termine. Isso porque
threads podem desativar ou mascarar sinais; se um thread mascarar o sinal

Sistemas operacionais.indd 29 18.12.09 19:37:12


30 sistemas operacionais

de cancelamento, ele no receber o sinal at que o sinal de cancelamento


seja reabilitado pelo thread.9 Entretanto, um thread no pode mascarar um
sinal de abortar.
Associar Em algumas implementaes de thread (por exemplo, Windows XP),
quando um processo iniciado, ele cria um thread primrio. O thread primrio
age como qualquer outro thread, exceto que, se ele voltar, o processo termina.
Para evitar que um processo termine antes que todos os seus threads concluam
a execuo, o thread primrio tipicamente dorme at que cada thread que ele
criar tenha concludo a execuo. Nesse caso, dizse que o thread primrio se
associa a cada um dos threads que cria. Quando um thread se associa a outro
thread, o primeiro no executa at que o ltimo termine.10

Embora a maioria das implementaes de thread suporte as operaes dis


cutidas nesta seo, outras operaes so especficas de bibliotecas de suporte a
threads particulares. Nas sees a seguir apresentamos diversas implementaes
populares de thread e discutimos questes que o projetista deve abordar ao criar
uma biblioteca de suporte a threads.

4.6 Modelos de thread


As implementaes de threads variam entre sistemas operacionais, mas quase
todos os sistemas suportam um dos trs sistemas primrios de funcionamento de
threads. Esta seo estuda os trs modelos mais populares: threads de usurio, threads
de ncleo e uma combinao desses dois.

4.6.1 Threads de usurio


Sistemas operacionais mais antigos suportavam processos que continham apenas
um nico contexto de execuo.11 Consequentemente, cada processo multithread era
responsvel por manter informaes de estado de thread, escalonar threads e fornecer
primitivas de sincronizao de threads. Os threads de usurio executam operaes de
suporte a threads no espao do usurio, o que significa que os threads so criados por
bibliotecas em tempo de execuo que no podem executar instrues privilegiadas nem
acessar as primitivas do ncleo diretamente.12 Threads de usurio so transparentes para
o sistema operacional esse trata cada processo multithread como um nico contexto
de execuo, o que significa que o sistema operacional despacha o processo multithread
como uma unidade, ao contrrio de despachar cada thread individual. Por essa razo,
implementaes de thread de usurio tambm so denominadas mapeamentos de
thread muitos-para-um porque o sistema operacional mapeia todos os threads de um
processo multithread para um nico contexto de execuo (Figura 4.3).

Sistemas operacionais.indd 30 18.12.09 19:37:12


G e r n c i a d o p r o c e s s a d o r 31

Figura 4.3 Threads de usurio

Um processo

Thread
Espao
do usurio
Contexto
Todos os threads de
de um processo execuo
mapeiam para um
nico contexto
de execuo Espao
do ncleo

Quando um processo emprega threads de usurio, so as bibliotecas de nvel de


usurio que realizam operaes de escalonamento e despacho nos threads do processo,
pois o sistema operacional no est ciente de que o processo contm mltiplos threads.
O processo multithread continua a executar at que seu quantum expire ou at sofrer
preempo pelo ncleo.13
A implementao de threads em espao de usurio em vez de em espao de
ncleo traz diversos benefcios. Threads de usurio no precisam que o sistema ope
racional suporte threads, logo, so mais portveis porque no dependem da API de
gerenciamento de threads de um sistema operacional particular. Uma outra vantagem
que, como a biblioteca de suporte a threads, e no o sistema operacional, que
controla o escalonamento de threads, os desenvolvedores de aplicaes podem ajustar
o algoritmo de escalonamento da biblioteca de suporte a threads para atender s
necessidades de aplicaes especficas.14
E mais, threads de usurio no invocam o ncleo para escalonamento de
decises ou procedimentos de sincronizao. Um sistema perde certo nmero de
ciclos de processador como sobrecarga quando ocorre uma interrupo, tal como
uma chamada ao sistema. Portanto, processos multithread de usurio que reali
zam operaes frequentes de suporte a threads (escalonamento e sincronizao)
beneficiam-se da baixa sobrecarga, comparados a threads que dependem do ncleo
para tais operaes.15
O desempenho do thread de usurio varia dependendo do sistema e do com
portamento do processo. Muitas das deficincias de threads de usurio esto rela
cionadas com o fato de que, para o ncleo, um processo multithread um nico

Sistemas operacionais.indd 31 18.12.09 19:37:14


32 sistemas operacionais

thread de controle. Por exemplo, threads de usurio no escalam bem para sistemas
multiprocessadores, porque o ncleo no pode despachar os threads de um processo
para mltiplos processadores simultaneamente, portanto, threads de usurio podem
resultar em desempenho abaixo do timo em sistemas multiprocessadores.16 Em um
mapeamento de threads muitos-para-um, todo o processo fica bloqueado quando
algum de seus threads requisita uma operao bloqueante de E/S, pois o processo
multithread inteiro o nico thread de controle que o sistema operacional reconhece.
Mesmo que o processo multithread contenha threads no estado pronto, nenhum de
seus threads pode executar at que o thread bloqueado passe para pronto, o que
pode fazer que o progresso da execuo se arraste no caso de processos multithread
que bloqueiam frequentemente. Aps o bloqueio de um thread de usurio, o ncleo
despachar um outro processo que pode conter threads de prioridade mais baixa
do que a dos threads prontos contidos no processo bloqueado. Por conseguinte,
threads de usurio tambm no suportam escalonamento de prioridades no mbito
do sistema, o que pode ser particularmente prejudicial para processos multithread
de tempo real.17 Note que algumas bibliotecas de suporte a threads traduzem cha
madas bloqueantes ao sistema para chamadas no bloqueantes para enfrentar esse
problema.18

4.6.2 Threads de ncleo


Threads de ncleo tentam resolver as limitaes dos threads de usurio mapeando
cada thread para seu prprio contexto de execuo. Consequentemente, threads de
ncleo em geral so descritos como mapeamento de thread um-para-um (Figura
4.4). Esses mapeamentos requerem que o sistema operacional fornea a cada thread
de usurio um thread de ncleo que o sistema operacional pode despachar. Threads
de ncleo so diferentes de processos pesados porque compartilham o espao de
endereamento do seu processo. Cada thread de ncleo tambm armazena dados
especficos de thread, como contedos de registradores e um identificador de thread
para cada thread do sistema. Quando um processo de usurio requisita um thread de
ncleo por meio de chamadas ao sistema definidas pela API do sistema operacional,
o sistema operacional cria um thread de ncleo que executa as instrues do thread
de usurio.
O mapeamento um-para-um oferece muitos benefcios. O ncleo pode despachar
os threads de um processo para diversos processadores ao mesmo tempo, o que pode
melhorar o desempenho de aplicaes projetadas para execuo concorrente.19 E mais,
o ncleo pode gerenciar cada thread individualmente, o que significa que o sistema
operacional pode despachar os threads prontos de um processo mesmo que um de
seus threads esteja bloqueado. Portanto, aplicaes que realizam bloqueio de E/S
podem executar outros threads enquanto esperam que a operao E/S seja concluda,
melhorando, assim, a interatividade para aplicaes que devem responder a entradas
de usurio e incrementando o desempenho em geral, contanto que a aplicao possa
se beneficiar de execuo concorrente.

Sistemas operacionais.indd 32 18.12.09 19:37:14


G e r n c i a d o p r o c e s s a d o r 33

Figura 4.4 Threads de ncleo

Um processo
Thread

Espao
do usurio Contexto
de
execuo

Cada thread
de usurio Espao
mapeia do ncleo
para um
contexto

Threads de ncleo habilitam o despachante do sistema operacional a reconhecer


cada thread de usurio individualmente. Se o sistema operacional implementa um
algoritmo de escalonamento por prioridade, um processo que usa threads de ncleo
pode ajustar o nvel de servio que cada thread recebe do sistema operacional de
signando prioridades de escalonamento a cada um de seus threads.20 Por exemplo,
um processo pode melhorar sua interatividade designando uma prioridade alta a um
thread que responda a requisies de usurio e prioridades mais baixas para seus
outros threads.
Threads de ncleo nem sempre so a soluo tima para aplicaes multithread.
Implementaes de thread de ncleo tendem a ser menos eficientes do que as de
usurio, pois as operaes de escalonamento e sincronizao envolvem o ncleo,
o que aumenta a sobrecarga. E mais, softwares que empregam thread de ncleo
normalmente so menos portveis do que os que empregam thread de usurio o
programador de aplicaes que usar threads de ncleo deve modificar o programa
para usar a API de thread para cada sistema operacional em que executar.21 Sistemas
operacionais em conformidade com interfaces padronizadas como POSIX reduzem
esse problema. Uma outra desvantagem que threads de ncleo tendem a consumir
mais recursos do que threads de usurio.22 Por fim, threads de ncleo requerem que
o sistema operacional gerencie todos os threads do sistema. Enquanto uma biblioteca
de nvel de usurio pode ser solicitada a gerenciar dezenas ou centenas de threads, o
sistema operacional pode ser solicitado a gerenciar milhares. Consequentemente, o de
senvolvedor de aplicaes deve estar seguro de que os subsistemas de gerenciamento
da memria e de escalonamento do sistema operacional tenham boa capacidade de
escalagem para grandes nmeros de threads.

Sistemas operacionais.indd 33 18.12.09 19:37:15


34 sistemas operacionais

4.6.3 Combinao de threads de usurio e de ncleo


Alguns sistemas operacionais como o Solaris e o Windows XP vm tentando
cobrir a lacuna entre mapeamentos muitos-para-um e um-para-um criando uma
implementao hbrida de threads. A combinao da implementao de threads de
usurio e de ncleo conhecida como mapeamento de thread muitos-para-muitos
(m-to-m) (Figura 4.5).23 Como seu nome sugere, essa implementao mapeia muitos
threads de usurio para um conjunto de threads de ncleo. Essa tcnica tambm
denominada mapeamento de thread m-to-n, porque o nmero de threads de
usurio e o nmero de threads de ncleo no precisam ser iguais.24
Mapeamentos de threads um-para-um requerem que o sistema operacional alo
que estruturas de dados que representam threads de ncleo. Consequentemente, a
quantidade de memria consumida pelas estruturas de dados do ncleo pode se tornar
significativa medida que cresce o nmero de threads no sistema. O mapeamento de
threads muitos-para-muitos reduz essa sobrecarga implementando o reservatrio de
threads (thread pooling). Essa tcnica permite que uma aplicao especifique o nmero
de threads de ncleo que requer. Por exemplo, na Figura 4.5, o processo P1 requisitou trs
threads de ncleo. Note que os threads T1 e T2 so mapeados para um nico thread de
ncleo um mapeamento muitos-para-um , o que exige que a aplicao mantenha
informao de estado para cada um de seus threads. Aconselhamos os desenvolvedores
de aplicaes a usar mapeamento muitos-para-um para threads que exibem um baixo
grau de paralelismo (ou seja, no podem se beneficiar da execuo simultnea). Os outros
threads do processo P1 (T3 e T4) so mapeados para um thread de ncleo. Esses threads
so gerenciados pelo sistema operacional como discutido anteriormente.
A existncia de um reservatrio de threads pode reduzir significativamente o
nmero de custosas operaes de criao e destruio de threads. Por exemplo, a

Figura 4.5 Modelo de operao de thread hbrido

Thread

T1 T2 T3 T4 T1 T2 T3 T1 T2
Contexto
Espao
de
do usurio
Cada thread de execuo
ncleo pode
mapear para um
ou mais threads
de usurio
Espao
do ncleo

Sistemas operacionais.indd 34 18.12.09 19:37:17


G e r n c i a d o p r o c e s s a d o r 35

Web e sistemas de banco de dados criam com frequncia um thread para responder
a cada requisio de servio que chega. O reservatrio de threads permite que os
threads de ncleo continuem no sistema depois que um thread de usurio morra.
Ento o thread de ncleo pode ser alocado a um novo thread de usurio que criado
mais tarde. Isso melhora os tempos de resposta do sistema em ambientes como o
de servidores Web, porque as requisies podem ser designadas para threads que
j existam no reservatrio. Esses threads de ncleo persistentes so denominados
threadsoperrios, pois executam, tipicamente, diversas funes diferentes, depen
dendo dos threads a eles designados.25
Uma vantagem do mapeamento de thread muitos-para-um que as aplicaes
podem melhorar seu desempenho personalizando o algoritmo de escalonamento
da biblioteca de suporte a threads. Todavia, se um nico thread de usurio ficar
bloqueado, o sistema operacional bloqueia todo o processo multithread. Uma outra
limitao do mapeamento de threads muitos-para-um que os threads de um pro
cesso no podem executar simultaneamente em processadores mltiplos. Ativaes
de escalonador tentam resolver essas limitaes dos threads de usurio. Uma ativao
de escalonador um thread de ncleo que pode notificar eventos a uma biblioteca
de suporte a threads de nvel de usurio (por exemplo, um thread bloqueou ou um
processador est disponvel). Esse tipo de thread de ncleo denominado ativao
de escalonador, porque a biblioteca de suporte a threads de usurio pode executar
operaes de escalonamento de thread quando ativada por uma notificao de
evento s vezes denominada upcall.
Quando um processo multithread gerado, o sistema operacional cria uma
ativao de escalonador que executa o cdigo de inicializao da biblioteca de su
porte a threads de usurio do processo, que cria threads e requisita processadores
adicionais para seus threads se necessrio. O sistema operacional cria uma ativao
de escalonador adicional para cada processador alocado a um processo, habilitando
a biblioteca de usurio a designar diferentes threads para executar simultaneamente
em processadores mltiplos.
Quando um thread de usurio bloqueia, o sistema operacional salva o estado
do thread para sua ativao de escalonador e cria uma ativao de escalonador para
notificar a biblioteca de usurio que um de seus threads bloqueou. Ento a biblio
teca de suporte a threads de usurio pode salvar o estado do thread bloqueado da
sua ativao de escalonador e designar um thread diferente para aquela ativao
de escalonador. Esse mecanismo impede que o processo multithread inteiro fique
bloqueado por causa do bloqueio de um de seus threads.26
A limitao primordial do modelo de thread muitos-para-muitos que ele com
plica o projeto do sistema operacional e no h um modo-padro para implement-
-lo.27 Por exemplo, o modelo muitos-para muitos do sistema Solaris 2.2 permitia que
aplicaes de usurio especificassem o nmero de threads de ncleo designados para

Sistemas operacionais.indd 35 18.12.09 19:37:17


36 sistemas operacionais

cada processo; o Solaris 2.6 introduziu as ativaes de escalonador. O interessante


que o Solaris 8 abandonou o mapeamento de thread muitos-para-muitos de seus
predecessores em favor de um esquema de mapeamento de thread um-para-um mais
simples e escalvel.28 O Windows XP, que no suporta ativaes de escalonador, ajusta
dinamicamente o nmero de threads operrios de seus reservatrios de threads em
resposta carga do sistema.29, 30

4.7 Consideraes sobre implementaes de threads


Nesta seo discutiremos diferenas entre implementaes de threads relativas
entrega de sinal de thread e cancelamento de thread. Essas diferenas destacam
questes fundamentais relativas a operaes e gerenciamento de threads.

4.7.1 Entrega de sinal de thread


Sinais interrompem a execuo do processo do mesmo modo que interrupes de
hardware, porm so gerados por software ou pelo sistema operacional ou pelos
processos de usurios. Sinais tornaram-se um mecanismo-padro de comunicao
interprocessos depois que apareceram no sistema operacional UNIX. O sistema ope
racional UNIX original no suportava threads, de modo que sinais foram projetados
para utilizao com processos.31
Quando o sistema operacional entrega um sinal a um processo, esse faz uma
pausa na sua execuo e invoca uma rotina de tratamento de sinal para responder
ao sinal. Quando o tratamento de sinal concludo, o processo retoma a execuo
(supondo que o processo no tenha sado).32
H dois tipos de sinais: sncrono e assncrono. Um sinal sncrono ocorre como
resultado direto de uma instruo executada pelo processo ou thread. Por exemplo,
se um processo ou thread executar uma operao ilegal de memria, o sistema
operacional envia ao processo um sinal sncrono indicando a exceo. Um sinal
assncrono ocorre devido a um evento no relacionado com a instruo corrente;
esses sinais devem especificar um identificador (ID) de processo para indicar o recep
tor do sinal. Sinais assncronos so comumente usados para notificar a concluso
de um processo E/S, suspender um processo, continuar um processo ou indicar que
um processo deve terminar.
Quando cada processo de um sistema contm um nico thread de controle, a
entrega do sinal direta. Se o sinal for sncrono (por exemplo, uma operao ilegal
de memria), ele ser entregue ao processo que est executando correntemente
no processador que iniciou o sinal (pela gerao de uma interrupo). Se o sinal for
assncrono, o sistema operacional poder entreg-lo ao processo ao qual se destina
se esse estiver executando correntemente, ou poder adicionar o sinal a uma fila de
sinais pendentes para ser entregue quando o processo receptor entrar em estado
de execuo.

Sistemas operacionais.indd 36 18.12.09 19:37:17


G e r n c i a d o p r o c e s s a d o r 37

Agora considere o caso de um processo multithread. Se o sinal for sncrono ser


razovel entreg-lo ao thread que estiver executando correntemente no processador
que iniciou o sinal (pela gerao de uma interrupo). Contudo, se ele for assncrono,
ser preciso que o sistema operacional possa identificar o receptor do sinal. Uma so
luo solicitar ao emissor que especifique um thread ID. Entretanto, se o processo
empregar uma biblioteca de threads de usurio, o sistema operacional no poder
determinar qual thread dever receber o sinal.
Como alternativa, o sistema operacional pode implementar sinais de modo tal
que o emissor especifique um ID de processo. Nesse caso o sistema operacional
deve decidir se entrega o sinal para todos os threads, para diversos threads ou para
um thread do processo. Pode parecer estranho, mas, na verdade, esse o modelo
de sinal que os sistemas UNIX e a especificao POSIX empregam, e o objetivo
proporcionar compatibilidade com aplicaes escritas originalmente para o sistema
operacional UNIX.
Segundo a especificao POSIX, processos enviam sinais especificando um iden
tificador de processo, e no um identificador de thread. Para resolver o problema
da entrega do sinal de thread o POSIX usa mascaramento de sinal. Uma mscara
de sinal permite que um thread desabilite sinais de um tipo particular para no
receber sinais daquele tipo. Assim, um thread pode mascarar todos os sinais, exceto
os que quiser receber (Figura 4.6). Nessa abordagem, quando o sistema operacional
recebe um sinal para um processo, ele o entrega a todos os threads do processo que
no esto mascarando sinais daquele tipo. Dependendo do tipo de sinal e da ao-
-padro, os sinais podem ser enfileirados para entrega aps o thread desmascarar
o sinal, ou o sinal pode ser simplesmente descartado. Por exemplo, na Figura 4.6
cada forma geomtrica representa um sinal de um tipo diferente (suspender, reto
mar, terminar). Nesse caso, o sistema operacional tenta entregar o sinal triangular
a um processo multithread. Note que ambos os threads 1 e 3 esto mascarando o
sinal triangular. O thread 2 no o est mascarando; portanto, o sistema operacional
entrega o sinal triangular ao thread 2 que ento invoca a rotina de tratamento de
sinais correspondente do processo.
Mascaramento de sinais permite que um processo divida a manipulao de sinais
entre diferentes threads. Por exemplo, um processador de texto pode conter um thread
que mascara todos os sinais, exceto eventos de teclado. O nico propsito desse
thread seria gravar toques de teclado do usurio. Mascaramento de sinais tambm
habilita o sistema operacional a controlar qual thread recebe um sinal.
Ao implementar um mecanismo POSIX de entrega de sinal, o sistema opera
cional tem de ser capaz de localizar uma mscara de sinal para cada thread. Um
mapeamento de thread um-para-um simplifica esse problema porque o sistema
operacional pode afixar uma mscara de sinal a cada thread de ncleo, que cor
responde exatamente a um thread de usurio. Contudo, se o sistema empregar

Sistemas operacionais.indd 37 18.12.09 19:37:17


38 sistemas operacionais

o modelo muitos-para-muitos, o mascaramento de sinais pode se tornar com


plexo. Considere o caso em que um sinal assncrono gerado por um processo
e o nico thread que no mascara o sinal no est correntemente em execuo.
Nesse caso o sistema operacional pode optar por adicionar o sinal a uma lista de
sinais pendentes ou descart-lo. Como regra geral, como os sinais so comumente
usados para notificar eventos importantes a processos e threads, o sistema ope
racional no deve descartar sinais [Nota: A especificao POSIX determina que o
sistema operacional pode descartar um sinal se todos os threads do processo o
tiverem mascarado, e a ao correspondente da rotina de tratamento de sinais
for ignorar o sinal.33]
Um modo de implementar sinais pendentes para um modelo de thread muitos-
-para-muitos criar um thread de ncleo para cada processo multithread que
monitora e entrega seus sinais assncronos. O sistema operacional Solaris 7 empre
gava um thread denominado Asynchronous Signal Lightweight Process (ASLWP)
que monitorava sinais e gerenciava sinais pendentes para que fossem entregues
ao thread apropriado, mesmo que o thread no estivesse executando no instante
da emisso do sinal.34
Se um processo multithread empregar uma biblioteca de nvel de usurio, o
sistema operacional simplesmente entregar todos os sinais ao processo porque no
pode distinguir threads individuais. A biblioteca de nvel de usurio registrar trata

Figura 4.6 Mascaramento de sinal

HWP (processo pesado)

Tratadores de sinal

Threads

T1 T2 T3

Mscaras de sinal

Legenda
- No mascarado
- Mascarado
Sinal

Sistemas operacionais.indd 38 18.12.09 19:37:20


G e r n c i a d o p r o c e s s a d o r 39

dores de sinais no sistema operacional que sero executados mediante o recebimento


de um sinal. A biblioteca de threads de usurio do processo poder, desse modo,
entregar o sinal a qualquer um de seus threads que no o mascaram.35, 36

4.7.2 Trmino de threads


Quando um thread termina, concluindo a execuo normalmente (por exemplo,
por uma chamada de sada a uma biblioteca de suporte a threads ou por sair do
mtodo que contm o cdigo do thread), o sistema operacional pode remover o
thread do sistema imediatamente. Threads tambm podem terminar prematura
mente devido a uma exceo (uma referncia ilegal memria) ou a um sinal de
cancelamento de um processo ou thread. Pelo fato de os threads cooperarem por
meios como modificao de dados compartilhados, uma aplicao pode produzir
resultados errados imperceptveis quando um de seus threads terminar inespera
damente. Consequentemente, bibliotecas de suporte a threads devem determinar
cuidadosamente como e quando remover o thread do sistema. Um thread pode
optar por desabilitar o cancelamento mascarando o sinal de cancelamento. Nor
malmente ele somente far isso enquanto estiver realizando uma tarefa que no
deva ser interrompida antes do trmino, como concluir uma modificao em uma
varivel compartilhada.37

4.8 POSIX e Pthreads


POSIX (Portable Operating Systems Interface for Computing Environments) um
conjunto de padres para interfaces de sistemas operacionais publicado pelo Portable
Application Standards Committee (PASC) do IEEE baseados, em grande parte, no UNIX
System V.38 A especificao POSIX define uma interface-padro entre threads e sua bi
blioteca de suporte a threads. Threads que usam a API de thread POSIX so denominados
Pthreads (s vezes tambm denominados threads POSIX ou threads POSIX 1003.1c).39 A
especificao POSIX no se preocupa com os detalhes da implementao da interface de
suporte a threads Pthreads podem ser implementados no ncleo ou por bibliotecas
de nvel de usurio.
POSIX determina que os registradores do processador, a pilha e a mscara de
sinal sejam mantidos individualmente para cada thread, e que qualquer outro recurso
deva ser acessvel globalmente a todos os threads no processo.40 Tambm define
um modelo de sinal que aborda muitas das preocupaes discutidas na Seo 4.7,
Consideraes sobre implementaes de threads. De acordo com o POSIX, quando
um thread gerar um sinal sncrono devido a uma exceo, tal como uma operao
ilegal de memria, o sinal ser entregue somente quele thread. Se o sinal no for
especfico para um thread, tal como um sinal para matar um processo, a biblioteca
de suporte a threads entregar o sinal a um thread que no o mascare. Se houver
mltiplos threads que no mascaram o sinal de matar, ele ser entregue a um desses

Sistemas operacionais.indd 39 18.12.09 19:37:20


40 sistemas operacionais

threads. Mais importante, no se pode usar o sinal de matar para terminar determi
nado thread quando um thread age obedecendo a um sinal de matar, o processo
inteiro, incluindo todos os seus threads, terminaro. Esse exemplo demonstra uma
outra propriedade importante do modelo de sinal POSIX: embora as mscaras de
sinais sejam armazenadas individualmente em cada thread, as rotinas de tratamento
de sinais so globais para todos os threads de um processo.41, 42
Para terminar um thread particular, o POSIX fornece uma operao de cancelamento
que especifica um thread visado e cujo resultado depende do modo de cancelamento
desse thread. Se o thread visado preferir cancelamento assncrono, ele poder ser
terminado a qualquer momento durante sua execuo. Se o thread adiar o cancela-
mento, ele no ser cancelado at verificar, explicitamente, se h uma requisio de
cancelamento. O cancelamento adiado permite que um thread conclua uma srie de
operaes antes de ser abruptamente terminado. Um thread tambm pode desabili-
tar o cancelamento, o que significa que ele no notificado sobre uma operao de
cancelamento ter sido requisitada.43
Alm das operaes comuns discutidas na Seo 4.5, Operaes de thread, a
especificao POSIX fornece funes que suportam operaes mais avanadas. Ela
permite que programas especifiquem vrios nveis de paralelismo e implementem uma
variedade de polticas de escalonamento, entre elas algoritmos definidos por usurio e
escalonamento em tempo real. A especificao tambm aborda sincronizao usando
travas, semforos e variveis de condio.44, 45, 46
Hoje, poucos dos sistemas operacionais mais populares fornecem implementaes
Pthread nativas completas, ou seja, no ncleo. Todavia, as bibliotecas de suporte
a threads do POSIX existem para fornecer uma ampla faixa de suporte para vrios
sistemas operacionais. Por exemplo, embora o Linux no esteja em conformidade
com o padro POSIX por definio, o projeto Native POSIX Thread Library (NPTL)
visa fornecer uma biblioteca de suporte a threads conforme o padro POSIX que
emprega threads de ncleo no Linux.47 Similarmente, a interface para a linha de
sistemas operacionais Microsoft Windows (API Win 32) no segue o padro POSIX,
mas os usurios podem instalar um subsistema POSIX. [Nota: O sistema operacional
Solaris 9 da Sun Microsystems fornece duas bibliotecas de suporte a threads: uma
biblioteca de Pthreads em conformidade com o padro POSIX e uma biblioteca de
threads herdada do Solaris (denominada threads de interface do usurio (UI). H
pouca diferena entre Pthreads e threads Solaris esse ltimo foi projetado para
que chamadas a funes de thread Pthreads e Solaris vindas de dentro da mesma
aplicao fossem vlidas.48

4.9 Threads Linux


O suporte para threads no sistema operacional Linux foi introduzido como threads
de usurio na verso 1.0.9 e como threads de ncleo na verso 1.3.56.49 Embora o

Sistemas operacionais.indd 40 18.12.09 19:37:20


G e r n c i a d o p r o c e s s a d o r 41

Linux suporte threads, importante observar que muitos dos seus subsistemas de
ncleo no distinguem entre threads e processos. De fato, o Linux aloca o mesmo
tipo de descritor de processo a processos e threads, ambos denominados tarefas.
O Linux usa a chamada ao sistema baseada no UNIX, denominada Fork, para criar
tarefas-filha. O Linux responde chamada ao sistema Fork criando uma tarefa que
contm uma cpia de todos os recursos de seu pai (por exemplo, espao de endere
amento, contedos de registradores, pilha).
Para habilitar o funcionamento de threads, o Linux fornece uma verso modi
ficada da chamada ao sistema Fork denominada clone. Similarmente Fork, clone
cria uma cpia da tarefa que est chamando na hierarquia do processo a cpia se
torna uma filha da tarefa que emitiu a chamada ao sistema clone. Diferentemente
de Fork, clone aceita argumentos que especificam quais recursos compartilhar com
o processo-filho. No nvel mais alto de compartilhamento de recursos, as tarefas
criadas por clone correspondem aos threads discutidos na Seo 4.2 Definio
de thread.
A partir da verso 2.6 do ncleo, o Linux fornece um mapeamento de thread
um-para-um que suporta um nmero arbitrrio de threads no sistema. Todas as
tarefas so gerenciadas pelo mesmo escalonador, o que significa que processos
e threads de igual prioridade recebem o mesmo nvel de servio. O escalonador
foi projetado para escalar bem at um grande nmero de processos e threads. A
combinao de um mapeamento um-para-um com um algoritmo de escalonamento
eficiente oferece ao Linux uma implementao de thread de alta escalabilidade.
Embora no suporte threads POSIX por definio, o Linux distribudo com uma
biblioteca de suporte a threads POSIX. No ncleo 2.4 uma biblioteca de suporte a
threads, denominada LinuxThreads, fornecia funcionalidade POSIX, mas no estava
totalmente em conformidade com a especificao POSIX. Um projeto mais recente,
Native POSIX Thread Library (NPTL), atingiu uma conformidade quase completa
com o POSIX e provavelmente se tornar a biblioteca de suporte a threads-padro
para o ncleo 2.6.50
Cada tarefa da tabela de processo armazena informaes sobre seu estado corrente
(por exemplo, em execuo, parada, morta). Uma tarefa que est no estado de execu-
o pode ser despachada para um processador (Figura 4.7). Uma tarefa entra no estado
adormecido quanto est dormindo, bloqueada ou no pode executar em um processador
por qualquer outra razo.
Ela entra no estado parado quando recebe um sinal de parada (isto , de
suspenso). O estado zumbi indica que uma tarefa foi terminada, mas ainda no
foi removida do sistema. Por exemplo, se uma tarefa contiver diversos threads, ela
entrar em estado zumbi enquanto notifica seus threads que recebeu um sinal de
trmino. Uma tarefa no estado morto pode ser removida do sistema.

Sistemas operacionais.indd 41 18.12.09 19:37:20


42 sistemas operacionais

Figura 4.7 Diagrama de transio de estado de tarefa do Linux

criao

Inserir na fila de execuo

ativa

Poro de Desbloquear
Despachada
tempo expira,
tarefa interativa adormecida
Nova
em execuo
poca
Poro Sinal de
parada
de tempo Continuar
expira

expirada Tarefa recebe


sinal de sair ou
de matar
Estados ativados
zumbi

Tarefa sai
do sistema

morta

4.10 Threads do Windows XP


No Windows XP um processo consiste em um cdigo de programa, um contexto
de execuo, recursos (por exemplo, arquivos abertos) e um ou mais threads associa
dos. O contexto de execuo contm itens como o espao virtual de endereamento
do processo e vrios atributos (por exemplo, atributos de segurana). Threads so,
na verdade, a unidade de execuo; executam uma parte do cdigo de um processo
no contexto do processo, usando recursos do processo. Alm do contexto do seu
processo, um thread contm seu prprio contexto de execuo que inclui sua pilha
de tempo de execuo, o estado dos registradores da mquina e diversos atributos
(por exemplo, prioridade de escalonamento).51
Quando o sistema inicializa um processo, ele cria um thread primrio que age
como qualquer outro thread, exceto que, se o thread primrio retornar, o processo
termina, a menos que o thread primrio determine explicitamente que o processo no
deva terminar. Um thread pode criar outros threads pertencentes a seu processo.52
Todos os threads pertencentes ao mesmo processo compartilham o espao de en
dereamento virtual daquele processo. Threads podem manter seus prprios dados
privados em armazenamento local de threads (Thread Local Storage TLS).

Sistemas operacionais.indd 42 18.12.09 19:37:23


G e r n c i a d o p r o c e s s a d o r 43

Fibras
Threads podem criar fibras; elas so semelhantes a threads, exceto que escalo
nada para execuo pelo thread que a cria, e no pelo escalonador. Fibras facilitam
aos desenvolvedores portar aplicaes que empregam threads de usurio. Uma fibra
executa no contexto do thread que a cria.53
A fibra deve manter informao de estado, como a prxima instruo a executar nos
registradores do processador. O thread armazena essa informao de estado para cada
fibra. O prprio thread tambm uma unidade de execuo e, por isso, deve converter-se
a si mesmo em uma fibra para separar sua prpria informao de estado de outras fibras
que executam em seu contexto. De fato, a API do Windows fora um thread a se converter
em uma fibra antes de criar ou escalonar outras fibras. O contexto da fibra permanece,
e todas as fibras associadas quele thread executam naquele contexto.54
Sempre que o ncleo escalonar um thread que foi convertido a uma fibra para
execuo, a fibra convertida ou uma outra fibra pertencente quele thread executar.
Uma vez obtido o processador, a fibra executa at que o thread em cujo contexto est
executando sofra preempo, ou at passar a execuo para uma outra fibra dentro
daquele thread. Do mesmo modo que threads possuem seu prprio armazenamento
local de threads (TLS), fibras possuem seu armazenamento local de fibras (Fiber
Local Storage FLS) que funciona para elas exatamente como o TLS funciona para
um thread. Uma fibra tambm pode acessar os TLSs de seus threads. Se uma fibra
se destruir (terminar), seu thread tambm terminar.55

Reservatrio de threads
O Windows XP tambm fornece um reservatrio de thread (thread pool) para cada
processo. Esse reservatrio consiste em vrios threads operrios, ou seja, threads de modo
ncleo que executam funes especificadas pelos threads de usurios. Como o nmero
de funes especificadas por threads de usurios pode exceder o nmero de threads
operrios, o Windows XP mantm as requisies para executar funes em uma fila. O
reservatrio de threads consiste em threads operrios que dormem at que uma requisio
entre na fila do reservatrio.56 O thread que colocar uma requisio em fila deve especificar
a funo a executar e fornecer informao de contexto.57 O reservatrio de threads
criado na primeira vez que um thread apresentar uma funo ao reservatrio.
O reservatrio de threads tem muitas finalidades. Servidores Web e bancos de dados
podem us-lo para manipular requisies de clientes (por exemplo, navegadores Web).
Em vez de incorrer na sobrecarga dispendiosa de criar e destruir um thread para cada
requisio, o processo simplesmente enfileira a requisio no seu reservatrio de threads
operrios. E mais, diversos threads que passam a maior parte do seu tempo dormindo
(esperando que ocorram eventos) podem ser substitudos por um nico thread operrio
que acorda toda vez que um desses eventos ocorrer. Alm disso, aplicaes podem usar
o reservatrio de threads para executar E/S assncrona enfileirando uma requisio no
seu reservatrio de threadsoperrios para executar as rotinas de concluso da E/S. Usar

Sistemas operacionais.indd 43 18.12.09 19:37:23


44 sistemas operacionais

reservatrio de threads pode tornar uma aplicao mais eficiente e simples, porque os
desenvolvedores no tm de criar e destruir um nmero to grande de threads. Contudo,
os reservatrios de threads transferem um certo controle do programador para o sistema,
o que pode introduzir ineficincia. Por exemplo, o sistema aumenta e reduz o tamanho
do reservatrio de threads de um processo em resposta a um volume de requisies; em
alguns casos, o programador pode estimar melhor quantos threads so necessrios.58

Estados de threads
No Windows XP, threads podem estar em qualquer um de oito estados (Figura
4.8). Um thread comea no estado inicializado durante a criao do thread. Uma
vez concluda a inicializao, o thread entra no estado pronto. Threads no estado
pronto esto esperando para usar um processador. Um thread que o despachante
decidiu que executar em seguida entra no estado de reserva enquanto espera sua
vez para obter um processador. Um thread est no estado de reserva, por exemplo,
durante o chaveamento de contexto de um thread que estava executando anterior
mente para aquele thread. Uma vez obtido o processador, o thread entra no estado
de execuo. Um thread sai do estado de execuo se concluir a execuo, exaurir
seu quantum, sofrer preempo, for suspenso ou esperar um objeto. Quando um
thread conclui suas instrues, ele entra no estado terminado. O sistema no precisa
necessariamente eliminar um thread terminado imediatamente, o que pode reduzir
a sobrecarga de criao do thread se o processo reinicializ-lo. O sistema elimina um
thread aps a liberao de seus recursos. Se um thread em execuo sofrer preempo
ou exaurir seu quantum, voltar ao estado de pronto.
Um thread em execuo entra no estado de espera enquanto estiver no aguardo
por um evento (por exemplo, um evento de concluso de E/S). E um outro thread (com
suficientes direitos de acesso), ou o sistema, tambm pode suspender um thread forando-
-o a entrar no estado de espera at que o thread seja retomado. Quando o thread concluir
sua espera, retornar ao estado de pronto ou entrar em estado de transio. O sistema
colocar um thread em estado de transio se seus dados no estiverem disponveis
correntemente (por exemplo, porque o thread no executou recentemente e o sistema
necessitou de sua memria para outras finalidades) mas, fora isso, o thread est pronto
para executar. O thread entrar em estado pronto assim que o sistema devolver a pilha
do ncleo do thread memria. O sistema coloca um thread no estado desconhecido
quando o estado do thread no estiver claro (usualmente devido a um erro).59, 60

4.11Estudo de caso do Java Multithread, parte I:


introduo a threads Java
A concorrncia introduzida por processos e threads causou um impacto signifi
cativo no projeto de software. Neste estudo de caso e em outros seguintes, daremos
exemplos de programas reais que demonstram e resolvem problemas introduzidos
pela concorrncia. Optamos por implementar esses programas em Java devido sua

Sistemas operacionais.indd 44 18.12.09 19:37:23


Gerncia do processador 45

Figura 4.8 Diagrama de transio de estado de thread do Windows XP

inicializado transio

ria a da
Criao mo ibiliz
Me pon
dis
Esp
pronto era
rc
on Esperar concluso,
Pr clu mas memria
e e mp
Execuo
indisponvel

s
pendente

o
o

de reserva em espera
exp
Pr

nd

o
m Despachado
ee o

era jet o
ir a

p s p
ob

do o E s

o
qu
ou u m pen
ant u s
um em execuo ou s

Trmino

desconhecido
terminado

portabilidade atravs das plataformas mais populares. Este estudo de caso presume
um conhecimento bsico de Java.
Nesta seo revisamos vrios mtodos relativos a threads na API Java. Usamos
muitos desses mtodos em exemplos de cdigos vivos. O leitor deve consultar dire
tamente a API Java para mais detalhes na utilizao de cada mtodo, especialmente
as excees apresentadas por cada um deles (consulte java.sun.com/j2se/1.4/docs/
api/java/lang/Thread.html).

A Classe Thread (package.java.lang) tem diversos construtores. O construtor public


Thread( String threadName )
constri um objeto Thread cujo nome threadName. O construtor public
Thread( )
constri um Thread cujo nome Thread concatenado com um nmero, como
Thread1, Thread2 e assim por diante.

O cdigo que faz o trabalho real de um thread colocado em seu mtodo run. O
mtodo run pode ser deixado de lado em uma subclasse de Thread ou implementado
em um objeto Runnable; Runnable uma interface Java que permite que o progra
mador controle o ciclo de vida de um thread com o mtodo run em um objeto de uma
classe que no estenda Thread.

Sistemas operacionais.indd 45 18.12.09 19:37:25


46 sistemas operacionais

Um programa lana a execuo de um thread chamando o mtodo start do thread,


o qual, por sua vez, chama o mtodo run. Depois de start ter lanado o thread, o
mtodo retorna imediatamente para quem o chamou. Desse modo, aquele que o
chamou executa concorrentemente com o thread lanado.
O mtodo static sleep chamado com um argumento que especifica quanto
tempo (em milissegundos) o thread que est executando correntemente deve dor
mir; enquanto um thread dorme, ele no disputa um processador, portanto outros
threads podem executar, o que d aos threads de prioridade mais baixa uma chance
de executar.
O mtodo setName determina o nome de um thread, o que facilita a depurao
permitindo que o programador identifique qual thread est executando. O mtodo
getName devolve o nome do Thread. O mtodo toString devolve uma String consis
tindo no nome do thread, na prioridade do thread e no ThreadGroup desse (anlogo
ao processo-pai de um grupo de threads). O mtodo static current Thread retorna
uma referncia ao Thread que est em execuo correntemente.
O mtodo join espera que o Thread para o qual a mensagem enviada termine
antes que o Thread chamador possa prosseguir; nenhum argumento ou um argu
mento de 0 milissegundo para um mtodo join indica que o Thread corrente esperar
eternamente que o Thread visado morra, antes que o Thread prossiga. Tal espera
pode ser perigosa; pode levar a dois problemas particularmente srios denominados
deadlock e adiamento indefinido.
O Java implementa sinalizao de thread usando o mtodo interrupt. Chamar o
mtodo interrupt em um thread que est bloqueado (porque o mtodo wait, join
ou sleep foi chamado) ativa (lana) seu tratador de excees InterruptedException.
O mtodo static interrupt retorna true se o thread corrente tiver sido interrompido;
caso contrrio, retorna false. Um programa pode invocar o mtodo isInterrupted
especfico de um thread para determinar se esse foi interrompido.

Criao e execuo de threads


A Figura 4.9 demonstra tcnicas bsicas de funcionamento de threads, como
construir objetos Thread e usar o mtodo Thread sleep. O programa cria trs threads
de execuo. Cada um deles exibe uma mensagem indicando que est indo dormir
durante um intervalo aleatrio de 0 a 5000 milissegundos e, depois, vai dormir.
Quando cada thread acorda, exibe seu nome, indica que parou de dormir, termina e
entra no estado morto. Voc ver que o mtodo main (o principal thread de execuo)
termina antes que a aplicao se encerre. O programa consiste em duas classes
ThreadTester (linhas 4-23), que cria os trs threads, e PrintThread (linhas 25-59), que
contm em seu mtodo run as aes que cada PrintThread executar.
A Classe PrintThread (linhas 25-59) estende Thread, de modo que cada objeto
PrintThread possa executar concorrentemente. A classe consiste em uma varivel de
instncia sleepTime (linha 27), um construtor (linhas 29-36) e um mtodo run (linhas
38-57). A varivel sleepTime armazena um valor inteiro aleatrio escolhido quando

Sistemas operacionais.indd 46 18.12.09 19:37:25


Gerncia do processador 47

Figura 4.9 Threads Java sendo criados, ativados, dormindo e imprimindo


(parte 1 de 2)
1 // Fig. 4.9: ThreadTester.java
2 // Mltiplos threads imprimindo em intervalos diferentes.
3
4 public class ThreadTester {
5
6 public static void main( String [] args )
7 {
8 // criar e dar nome a cada thread
9 PrintThread thread1 = new PrintThread( thread1 );
10 PrintThread thread2 = new PrintThread( thread2 );
11 PrintThread thread3 = new PrintThread( thread3 );
12
13 System.err.println( Ativando threads );
14
15 thread1.start(); // ative thread1; coloqueo no estado pronto
16 thread2.start(); // ative thread2; coloqueo no estado pronto
17 thread3.start(); // ative thread3; coloqueo no estado pronto
18
19 System.err.println( Threads ativados, main termina\n );
20
21 } // termine main
22
23 } // temine classe ThreadTester
24
25 // classe PrintThread controla execuo do thread
26 classe PrintThread estende Thread {
27 private int sleepTime;
28
29 // designe nome ao thread chamando construtor superclasse
30 public PrintThread( String name )
31 {
32 super( name );
33
34 // escolha tempo de sono aleatrio entre 0 e 5 segundos
35 sleepTime = ( int ) ( Math.random( ) * 5001 );
36 } // termine construtor PrintThread
37
38 // mtodo run o cdigo a ser executado pelo novo thread
39 public void run( )
40 {
41 // ponha thread para dormir por perodo de tempo sleepTime
42 try {
43 System.err.println( getName() + vai dormir por +
44 sleepTime + milissegundos );
45
46 Thread.sleep( sleepTime );

Sistemas operacionais.indd 47 18.12.09 19:37:30


48 sistemas operacionais

Figura 4.9 Threads Java sendo criados, ativados, dormindo e imprimindo


(Parte 2 de 2)

47 } // termine try
48
49 // se thread interrompido durante o sono, imprima cpia da pilha ( stack trace )
50 catch ( InterruptedException exception ) {
51 exception.printStackTrace();
52 } // termine catch
53
54 // imprima nome do thread
55 System.err.println( getName() + terminou de dormir );
56
57 } // termine mtodo run
58
59 } // termine classe PrintThread

Amostra de resultado 1:
Ativando threads
Threads ativados, main termina
thread1 vai dormir por 1217 milissegundos
thread2 vai dormir por 3989 milissegundos
thread3 vai dormir por 662 milissegundos
thread3 terminou de dormir
thread1 terminou de dormir
thread2 terminou de dormir

Amostra de resultado 2:
Ativando threads
thread1 vai dormir por 314 milissegundos
thread2 vai dormir por 1990 milissegundos
Threads ativados, main termina
thread3 vai dormir por 3016 milissegundos
thread1 terminou de dormir
thread2 terminou de dormir
thread3 terminou de dormir

Sistemas operacionais.indd 48 18.12.09 19:37:32


G e r n c i a d o p r o c e s s a d o r 49

um novo construtor de objeto PrintThread chamado. Cada thread controlado por


um objeto PrintThread dorme pelo tempo especificado pelo sleepTime do objeto
PrintThread correspondente e, ento, apresenta seu nome.
O construtor PrintThread (linhas 29-36) inicializa sleepTime para um nmero inteiro
aleatrio de 0 a 5000. Quando um PrintThread designado a um processador pela
primeira vez, seu mtodo run comea a executar.
As linhas 43-44 exibem uma mensagem indicando o nome do thread que est em
execuo e determinando que o thread durma por um certo nmero de milissegundos.
A linha 43 usa o mtodo getName do thread que est em execuo para obter o nome
do thread que foi especificado, como um argumento de tipo cadeia de caracteres, para
o construtor PrintThread e passado para o construtor superclasse Thread na linha 32.
Note que a linha 43 usa System.err para imprimir a mensagem porque o System.err no
tem buffer, o que significa que ele imprime seu argumento imediatamente depois de ser
chamado. A linha 46 invoca o mtodo Thread esttico sleep para colocar o thread no
estado adormecido. Nesse ponto, o thread perde o processador, e o sistema permite que
outro thread execute. Quando o thread acorda, entra novamente no estado pronto no
qual espera at que o sistema lhe designe um processador. Quando o objeto PrintThread
entra novamente no estado em execuo, a linha 55 apresenta o nome do thread em uma
mensagem que indica que o thread terminou de dormir; ento o mtodo run termina, o
que coloca o thread no estado morto, ponto em que seus recursos podem ser liberados.
O mtodo ThreadTester main (linhas 6-21) cria e d nome a trs objetos Print
Thread (linhas 9-11). Ao depurar um programa multithread, esses nomes identificam
quais threads esto em execuo. As linhas 15-17 invocam o mtodo start de cada
thread para fazer a transio de todos os trs objetos PrintThread do estado nascido
para o estado pronto. O mtodo start retorna imediatamente de cada invocao;
desse modo a linha 19 apresenta uma mensagem indicando que os threads foram
ativados. Note que todo o cdigo desse programa, exceto o do mtodo run, executa
no thread main. O construtor PrintThread tambm executa no thread main, pois
cada objeto PrintThread criado no mtodo main. Quando o mtodo main termina
(linha 21), o programa em si continua executando, porque ainda h threads vivos
(threads que foram ativados e ainda no chegaram ao estado morto) e que no so
daemon. O programa termina quando seu ltimo thread morre. Quando o sistema
designa um processador para um PrintThread pela primeira vez, o thread entra no
estado em execuo e o mtodo run do thread comea a executar.
As amostras de resultados desse programa mostram o nome de cada thread e o tempo
de sono quando vai dormir. O thread que tem o menor tempo de sono normalmente
acorda primeiro, indica que acabou de dormir e termina. Note que, na segunda amostra
de resultado, o thread1 e o thread2 apresentam, cada um, seu nome e tempo de sono
antes que o mtodo main conclua sua execuo. Essa situao demonstra que, uma vez
que mltiplos threads estejam no estado pronto, o processador pode ser designado para
qualquer um deles.

Sistemas operacionais.indd 49 18.12.09 19:37:32