Skip to content

Threads

Day edited this page Apr 7, 2025 · 4 revisions

Threads

Os códigos descritos nesse tópico são referentes à seção de threads.

Podem ser encontrados tanto aqui quanto nesse link.

exemplo_pthread.c

Visualizar o tid da thread

Código:

#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>

void* funcao_thread(void* arg)
{
    printf("\tNova thread criada com PID %d e TID %d\n", 
            getpid(), gettid());
    sleep(50);
    printf("Thread com o ID %d finalizada.\n", gettid());
    return NULL;
}

int main()
{
    pthread_t thread1, thread2;

    printf("Processo pesado PID %d\n", getpid());
    
    pthread_create(&thread1, NULL, &funcao_thread, NULL);
    
    pthread_create(&thread2, NULL, &funcao_thread, NULL);

    //printf("Identificador da thread %lu\n",thread1);
    //printf("Identificador da thread %lu\n",thread2);
    
    sleep(20);
    
    printf("Main finalizando\n");

    return 0;
}

Compilar e Executar:

gcc -pthread exemplo_pthread.c -o exemplo_pthread
./exemplo_pthread

Nesse exemplo, serão criadas duas threads usando o pthread_create, que executarão duas instâncias da função funcao_thread.

Note

Não serão criados dois processos novos, como acontece usando o fork. Sendo assim, será o mesmo processo, mas executando duas instâncias da função que ainda compartilham os mesmos dados, e o mesmo código.

Cada uma das threads vai imprimir no terminal o PID do processo e o TID, o ID da thread, após isso, a chamada da função sleep(50), faz com que as duas fiquem em pausa por 50 segundos.

É importante notar que nesse exemplo, o programa vai esperar apenas 20 segundos, por conta do sleep(20) que está depois das duas pthread_create que se encontram no main.

Exemplo de saída:

Processo pesado PID 28910
        Nova thread criada com PID 28910 e TID 28911
        Nova thread criada com PID 28910 e TID 28912
Main finalizando

Isso significa que as threads não terão tempo de serem concluídas, pois após 20 segundos o programa acaba e as threads são encerradas, isso pode ser notado no exemplo de saída, o segundo print que está presente na função das threads não foi executado. Pois o main não vai esperar as threads finalizarem ao menos que isso seja indicado. Para isso, assim como no fork tínhamos o wait(0), para threads temos o pthread_join, assim o main só irá finalizar quando todas as threads forem finalizadas.

pthread_join.c

Código modificado com o pthread_join:

#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>

void* funcao_thread(void* arg)
{
    printf("\tNova thread criada com PID %d e TID %d\n", 
            getpid(), gettid());
    sleep(50);
    printf("Thread com o ID %d finalizada.\n", gettid());
    return NULL;
}

int main()
{
    pthread_t thread1, thread2;

    printf("Processo pesado PID %d\n", getpid());
    
    pthread_create(&thread1, NULL, &funcao_thread, NULL);
    
    pthread_create(&thread2, NULL, &funcao_thread, NULL);

    //printf("Identificador da thread %lu\n",thread1);
    //printf("Identificador da thread %lu\n",thread2);
    
    sleep(20);

    printf("Main esperando as threads finalizarem\n");

    // aguardando as threads finalizarem
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    printf("Main finalizando\n");


    return 0;
}

Compilar e Executar:

gcc -pthread exemplo_thread.c -o exemplo_thread
./exemplo_thread

Exemplo de saída:

Processo pesado PID 7167
        Nova thread criada com PID 7167 e TID 7168
        Nova thread criada com PID 7167 e TID 7169
Main esperando as threads finalizarem
Thread com o ID 7169 finalizada.
Thread com o ID 7168 finalizada.
Main finalizando

Com essa modificação, o main esperou as duas threads finalizarem para então continuar a execução, isso pode ser observado na saída do programa onde o conteúdo do segundo print que estava na função funcao_thread apareceu no terminal, sinalizando que as threads terminaram de executar, diferentemente do exemplo anterior que não tínhamos usado o pthread_join.

Note

Nesse exemplo de saída é interessante notar que foi criada primeiramente uma thread com o ID 7168, e outra com o ID 7169, elas foram criadas nessa ordem, mas quando elas foram finalizar podemos notar que primeiro finalizou a com o ID 7169 e depois a de ID 7168, porque isso aconteceu?

concorrentes.c

Mostra a execução "simultânea" de duas threads

Código:

#include <pthread.h>
#include <stdio.h>

void * ProcessoLeve1()
{
    int i;
    printf("T1\n");
    for (i = 1; i < 100000; i++)
    //for (i = 1; i < 100; i++)
        printf("\tThread 1 - %d\n",i);
}

void * ProcessoLeve2()
{
    int i;
    printf("T2\n");
    for (i = 100000; i < 200000; i++)
    //for (i = 100; i < 200; i++)
        printf("\t\tThread 2 - %d\n",i);
}

int main()
{
    pthread_t thread1, thread2;
    
    pthread_create(&thread1, NULL, ProcessoLeve1, NULL);
    pthread_create(&thread2, NULL, ProcessoLeve2, NULL);
    
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    
    pthread_detach(thread1);
    pthread_detach(thread2);

    return 0;
}

Compilar e Executar:

gcc -pthread concorrentes.c -o concorrentes
./concorrentes

Nesse exemplo, também são criadas duas threads com o pthread_create para executar duas funções diferentes: ProcessoLeve1 e ProcessoLeve2.

O ProcessoLeve1 apenas imprime na tela: Thread 1 - i, onde i é incrementado de 1 até 99999.

O ProcessoLeve2 apenas imprime na tela: Thread 2 - i, onde i é incrementado de 100000 até 199999.

Exemplo de saída:

T2
		Thread 2 - 100000
		Thread 2 - 100001
		Thread 2 - 100002
                       ...
		Thread 2 - 100010
		Thread 2 - 100011
		Thread 2 - 100012
T1
		Thread 2 - 100013
	Thread 1 - 1
	Thread 1 - 2
	Thread 1 - 3
	Thread 1 - 4
		Thread 2 - 100014
	Thread 1 - 5
		Thread 2 - 100015
	Thread 1 - 6
	Thread 1 - 7
		Thread 2 - 100016
	Thread 1 - 8
	Thread 1 - 9
		Thread 2 - 100017
	Thread 1 - 10
		Thread 2 - 100018
		Thread 2 - 100019
		Thread 2 - 100020
		Thread 2 - 100021
	Thread 1 - 11
		Thread 2 - 100022
	Thread 1 - 12
	Thread 1 - 13
	Thread 1 - 14
		Thread 2 - 100023
	Thread 1 - 15
		Thread 2 - 100024
	Thread 1 - 16
	Thread 1 - 17
	Thread 1 - 18
		Thread 2 - 100025

Ao executar o código, é possível notar que os dois prints das funções são executados aleatoriamente. Pode ser que seja impresso 7 da thread1 e 4 da thread2 por vez. Ou 6 da thread1 e 20 da thread2, não tem como prever. Nesse exemplo de saída se encontra as primeiras linhas que foram geradas pelo programa, podemos notar que a thread dois conseguiu acesso primeiro ao processador do que a thread um.

Isso acontece porque as duas threads criadas estão concorrendo pelo processador.

Cada thread quer usar os recursos do processador para executar e finalizar a sua tarefa, mas não só elas como também todos os outros processos que estão sendo executados no computador. Isso leva à execução alternada e completamente aleatória das duas funções.

Note

Isso também aconteceu no exemplo anterior, todas as threads e processos concorrem pelo uso do processador, por isso a thread com o ID 7169 terminou antes da outra de ID 7168 que foi criada primeira, foi a aleatoriedade do acesso ao processador que fez com que isso fosse possível, mas isso não impede que a thread que foi criada primeiro não finalize antes da outra.

Clone this wiki locally