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) ;
}
  1. Analise seu código e o comente detalhadamente.

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, como printf.
  • <stdlib.h>: Biblioteca para funções de utilidade geral, como exit.
  • <unistd.h>: Biblioteca que fornece acesso a funcionalidades POSIX, como sleep.

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, usamos void * e depois convertemos para long.
  • 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:
        1. Endereço onde o ID da thread será armazenado (&thread[i]).
        2. NULL: Atributos padrão para a thread.
        3. threadBody: Função que a thread vai executar.
        4. (void *) i: Passa o ID da thread como argumento para threadBody.
      • Retorno: Retorna 0 se a thread for criada com sucesso. Se não, retorna um código de erro.
    • 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.
  • 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 e pthread_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ó aceita void * 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.

Exercícios relacionados