Dado o programa abaixo:
thread-create.c
/*
Criação de threads POSIX em UNIX.
Compilar com gcc -Wall thread-create.c -o thread-create -lpthread
Carlos Maziero, DINF/UFPR 2020
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define NUM_THREADS 16
void *threadBody (void *id)
{
long tid = (long) id ; // ID da thread
printf (t%02ld: Olá!\n, tid) ;
sleep (3) ;
printf (t%02ld: Tchau!\n, tid) ;
pthread_exit (NULL) ;
}
int main (int argc, char *argv[])
{
pthread_t thread [NUM_THREADS] ;
long i, status ;
for (i=0; i<NUM_THREADS; i++)
{
printf (Main: criando thread %02ld\n, i) ;
status = pthread_create (&thread[i], NULL, threadBody, (void *) i) ;
if (status)
{
perror (pthread_create) ;
exit (1) ;
}
}
printf (Main: fim\n) ;
pthread_exit (NULL) ;
}
- Analise seu código e o comente detalhadamente.
thread-create.c
/*
Criação de threads POSIX em UNIX.
Compilar com gcc -Wall thread-create.c -o thread-create -lpthread
Carlos Maziero, DINF/UFPR 2020
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define NUM_THREADS 16
void *threadBody (void *id)
{
long tid = (long) id ; // ID da thread
printf (t%02ld: Olá!\n, tid) ;
sleep (3) ;
printf (t%02ld: Tchau!\n, tid) ;
pthread_exit (NULL) ;
}
int main (int argc, char *argv[])
{
pthread_t thread [NUM_THREADS] ;
long i, status ;
for (i=0; i<NUM_THREADS; i++)
{
printf (Main: criando thread %02ld\n, i) ;
status = pthread_create (&thread[i], NULL, threadBody, (void *) i) ;
if (status)
{
perror (pthread_create) ;
exit (1) ;
}
}
printf (Main: fim\n) ;
pthread_exit (NULL) ;
}
Passo 1
Beleza, vamos analisar o exercício que pede para comentar detalhadamente um código em C que cria threads usando POSIX threads. O assunto aqui é programação concorrente com threads em sistemas UNIX. Para resolver isso, vamos entender cada parte do código, o que as diferentes funções e comandos fazem, e como as threads são gerenciadas nesse programa.
Passo 2
Primeiro, o código começa com alguns comentários que explicam o propósito do programa e como compilá-lo. Isso é bom para quem vai usar o código entender o que esperar.
/*
Criação de threads POSIX em UNIX.
Compilar com gcc -Wall thread-create.c -o thread-create -lpthread
Carlos Maziero, DINF/UFPR 2020
*/
Aqui, está dizendo que vamos criar threads usando POSIX em UNIX e que precisamos compilar com a opção
-lpthread
para linkar a biblioteca de threads.Passo 3
Em seguida, temos as inclusões das bibliotecas necessárias:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
<pthread.h>
: Biblioteca padrão para trabalhar com threads POSIX.<stdio.h>
: Biblioteca para entrada e saída padrão, comoprintf
.<stdlib.h>
: Biblioteca para funções de utilidade geral, comoexit
.<unistd.h>
: Biblioteca que fornece acesso a funcionalidades POSIX, comosleep
.
Passo 4
Definimos uma constante:
#define NUM_THREADS 16
Aqui,
NUM_THREADS
está definido como 16, o que significa que o programa vai criar 16 threads.Passo 5
Vamos olhar para a função que será executada por cada thread:
void *threadBody (void *id)
{
long tid = (long) id ; // ID da thread
printf ("t%02ld: Olá!\n", tid) ;
sleep (3) ;
printf ("t%02ld: Tchau!\n", tid) ;
pthread_exit (NULL) ;
}
- Parâmetro
void *id
: É um ponteiro genérico que recebe o ID da thread. Como C não suporta diretamente passagem de tipos diferentes, usamosvoid *
e depois convertemos paralong
. - Conversão para
long
:long tid = (long) id;
converte o ponteiro para um número inteiro que representará o ID da thread. printf
: Primeiro, a thread imprime “tXX: Olá!”, onde XX é o ID da thread, com dois dígitos.sleep(3)
: A thread pausa por 3 segundos.- Segundo
printf
: Depois do sono, imprime “tXX: Tchau!”. pthread_exit(NULL)
: Termina a execução da thread.
Passo 6
Agora, vamos para a função
main
:int main (int argc, char *argv[])
{
pthread_t thread [NUM_THREADS] ;
long i, status ;
for (i=0; i<NUM_THREADS; i++)
{
printf ("Main: criando thread %02ld\n", i) ;
status = pthread_create (&thread[i], NULL, threadBody, (void *) i) ;
if (status)
{
perror ("pthread_create") ;
exit (1) ;
}
}
printf ("Main: fim\n") ;
pthread_exit (NULL) ;
}
-
Declaração de variáveis:
pthread_t thread[NUM_THREADS];
: Um array para guardar os identificadores das threads criadas.long i, status;
: Variáveis para o loop e para verificar status da criação das threads.
-
Loop
for
:for (i=0; i<NUM_THREADS; i++)
: Vai de 0 a 15, criando 16 threads.printf
: Imprime que está criando a thread com o ID atual.pthread_create
:- Parâmetros:
- Endereço onde o ID da thread será armazenado (
&thread[i]
). NULL
: Atributos padrão para a thread.threadBody
: Função que a thread vai executar.(void *) i
: Passa o ID da thread como argumento parathreadBody
.
- Endereço onde o ID da thread será armazenado (
- Retorno: Retorna 0 se a thread for criada com sucesso. Se não, retorna um código de erro.
- Parâmetros:
- Verificação de
status
:- Se
status
não for 0, significa que houve um erro na criação da thread. perror
: Imprime a mensagem de erro correspondente.exit(1)
: Encerra o programa com status de erro.
- Se
-
Após o loop:
printf("Main: fim\n")
: Informa que o processo principal terminou de criar as threads.pthread_exit(NULL)
: Faz com que o processo principal espere todas as threads terminarem antes de finalizar completamente.
Passo 7
Conceitos Teóricos Aplicados:
- Threads: São unidades de execução dentro de um processo que compartilham o mesmo espaço de memória, permitindo a execução simultânea de tarefas.
- Biblioteca pthread: Padrão em sistemas UNIX para manipulação de threads, oferecendo funções como
pthread_create
epthread_exit
. - Concorrência: Permite que múltiplas threads rodem aparentemente ao mesmo tempo, melhorando a eficiência do programa.
- Passagem de Argumentos: Como
pthread_create
só aceitavoid *
como argumento, usamos casting para passar o ID da thread. - Sincronização: Neste código, não há sincronização explícita, já que as threads apenas imprimem mensagens e dormem.
Resposta
O programa em C utiliza a biblioteca pthread para criar 16 threads, cada uma identificada por um número de 00 a 15. Cada thread, ao ser criada, imprime uma mensagem de “Olá!”, espera 3 segundos e então imprime “Tchau!”, finalizando sua execução. O processo principal (
main
) gerencia a criação das threads, imprimindo mensagens indicando a criação de cada uma e, ao final, informa que terminou de criar todas as threads. Utilizando conceitos de programação concorrente, o programa demonstra como múltiplas threads podem ser executadas simultaneamente, cada uma realizando suas tarefas independentemente, enquanto o processo principal aguarda todas terminarem antes de finalizar completamente.