2. Threads
Threads (processos leves) são processos que compartilham o
contexto. De uma forma simples, pode-se pensar em threads como
sendo funções dentro de um mesmo programa e que podem ser
executadas concorrentente.
Um processo tradicional é igual a um processo com uma única
thread.
Diferentes threads de um mesmo processo podem ser
alocadas em processadores diferentes se a máquina for
multiprocessada.
Laboratório de Programação II – Threads
3. Vantagens
As vantagens de se utilizar threads ao invés de várias instâncias
do mesmo programa são:
Economia de recursos: utilizando threads não é necessário
replicar a seção de código e dados para cada processo.
Velocidade: a troca de contexto é muito mais rápida.
Comunicação: como as threads compartilham a mesma área
de dados, a comunicação entre as threads é simples e
eficiente.
Laboratório de Programação II – Threads
As threads fornecem uma maneira bastante eficiente de se conseguir
paralelismo em máquinas multiprocessadas.
4. Threads de Kernel e Usuário
Os tipos básicos de threads são:
Threads do kernel: threads admitidas diretamente pelo
kernel.
Threads do usuário: gerenciamento de thread feito pela
biblioteca de threads em nível de usuário.
Laboratório de Programação II – Threads
O Linux possui uma API para manipulação de threads
implementada usando o padrão POSIX.
Para usar esta API, precisamos incluir o arquivo de cabeçalho
<pthread.h> e linkar com a biblioteca -lpthread
5. Função pthread_create
Para criarmos uma thread, utilizamos a função pthread_create:
pthread_create(&pthread_id, NULL, &funcao, NULL);
pthread_id: ponteiro para uma variável do tipo pthread_t, que
conterá o identificador (ID) da thread recém criada.
NULL (segundo parâmetro): ponteiro para os atributos.
Os atributos são armazenados em uma variável do tipo
pthread_attr_t. Um valor NULL indica o uso de valores default.
funcao: um ponteiro para a função a ser executada pela thread.
NULL (último parâmetro): um void* que é passado como
argumento para rotina (pthread_t). Use NULL se não for passar
nenhum parâmetro.
Laboratório de Programação II – Threads
6. Passando dados
Para passarmos dados para uma thread, utilizamos o parâmetro
void*. A melhor maneira de passarmos os dados é definir uma
estrutura e passar um ponteiro para este tipo de estrutura:
Laboratório de Programação II – Threads
7. Passando dados
A função de thread precisa converter o void* em thread_alfa:
Laboratório de Programação II – Threads
9. Joining
O programa principal executa de forma concorrente com as
threads. Se quisermos que programa principal espere até que uma
thread tenha concluído, utilizamos a função pthread_join:
pthread_join(thread_id, NULL);
Se o segundo parâmetro não for NULL, ele receberá o valor de
retorno da função de thread.
Enquanto a função join não for chamada, a thread fica em um
estado ‘zumbi’, pois ela precisa guardar o valor de retorno.
Após a chamada de pthread_join, os recursos da thread são
liberados.
Laboratório de Programação II – Threads
10. Encerramento
Uma thread pode ser encerrada de várias formas:
Quando a função de thread é encerrada (return).
Quando é chamada a função pthread_exit(NULL).
O parâmetro é o retorno da thread (pode ser NULL se o retorno
for ignorado).
Laboratório de Programação II – Threads
É sempre preferível encerrar uma thread naturalmente do que cancelá-la a
força.
11. Exemplo - Hello World
Laboratório de Programação II – Threads
12. Atividade 5 (2 pontos da A4)
1. Faça um programa que possua uma função (procedimento) de thread que
verifique se um inteiro é par ou impar (desconsiderar o zero). Esta função
recebe como parâmetro o inteiro (n) e mostra para o usuário "Par" ou
"Impar". O programa principal lê (n) do teclado, cria uma thread para a
função parimpar (passando o n), aguarda até que ela seja concluída (join).
2. Faça um programa que cria duas threads. Ambas recebem como
parâmetro um ponteiro para a estrutura thread_alfa, vista anteriormente, e
chamam a mesma função func, também vista anteriormente. Uma thread
deve imprimir 300 ‘a’, e a outra 200 ‘z’ (estes valores e caracteres são
passados através de um ponteiro para thread_alfa). O programa principal
simplesmente espera as threads terminarem (join) e encerra.
Repare para as threads recebendo ponteiros para estruturas e concorrendo
pelo processador.
Dica: Dentro da função, converta o void* valores recebido para
thread_alfa: thread_alfa* p = (thread_alfa*) valores;
Cada grupo deverá submeter via Moodle UM arquivo compactado (Grupo_0.zip)
contendo a implementação em C até o final da aula de 08/08.
Laboratório de Programação II – Threads
13. Referências
Barney, B. POSIX Threads Programming. Lawrence Livermore
National Laboratory.
Heinen, M. R. Programação Avançada em C no GNU/Linux. Capítulo
04: Threads. UNISINOS.
Laboratório de Programação II – Threads