Controle de Threads no Linux

Este artigo apresenta o controel de threads no Linux, incluindo criação (veja o conteúdo anterior), término, espera e separação.

Controle de Threads

Término de Threads

A função pthread_t pthread_self(void) é utilizada para obter o identificador da thread atual.

Para terminar apenas uma thread específica sem encerrar todo o processo, existem três abordagens:

  1. Retornar diretamente da função da thread. Esta opção não se aplica à thread principal, pois retronar de main é equivalente a chamar exit.
  2. A thread pode chamar pthread_exit para terminar-se.
  3. Uma thread pode usar pthread_cancel para encerrar outra thread no mesmo prcoesso. Usar exit() dentro de uma thread encerra todo o processo.
#include <vector>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <iostream>

std::string ToHex(pthread_t tid)
{
    char id[64];
    snprintf(id, sizeof(id), "0x%x", tid);
    return id;
}

void *threadRoutine(void *args)
{
    std::string name = static_cast<const char*>(args);
    int cnt = 3;
    while(cnt--)
    {
        std::cout << "nova thread em execução, nome: " << name << " , ID: " << ToHex(pthread_self()) << std::endl;
        sleep(1);
    }
    //return nullptr;	//encerramento da thread
    //exit(13); 	//encerramento do processo
    pthread_exit(nullptr);	//encerramento da thread
    std::cout << "A thread terminou anteriormente" << std::endl;
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, threadRoutine, (void*)"thread-1");
    while(true)
    {
        std::cout << "main: ID da thread: " <<  ToHex(tid) << std::endl;
        sleep(1);
    }
    return 0;
}

  • return nullptr;
  • exit();
  • pthread_exit(nullptr);
  • pthread_cancel;

Espera de Threads

Por que esperar por threads?

Quando uma thread termina, seu espaço de memória não é liberado e permanece no endereço do processo. Criar novas threads não reutiliza o espaço de memória da thread anterior.

Os valores armazenados em value_ptr dependem do modo de término da thread:

  1. Se a thread termina com return, o valor apontado por value_ptr contém o valor de retorno da função da thread.
  2. Se a thread foi cancelada com pthread_cancel, o valor apontado é PTHREAD_CANCELED.
  3. Se a thread chama pthread_exit, o valor apontado contém o argumento passado para pthread_exit.
  4. Se não se deseja informações sobre o estado de término, pode-se passar NULL como value_ptr.

Aqui demonstramos os casos 3 e 4.

#include <vector>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <iostream>

void *threadRoutine(void *args)
{
    std::string name = static_cast<const char*>(args);
    int cnt = 3;
    while(cnt--)
    {
        std::cout << "nova thread em execução, nome: " << name << " , ID: " << ToHex(pthread_self()) << std::endl;
        sleep(1);
    }
    
    //----------------------------------------------------------encerramento da thread
    pthread_exit((void*)"thread-1 encerrada...");
    std::cout << "A thread terminou anteriormente" << std::endl;
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, threadRoutine, (void*)"thread-1");
    void *ret = nullptr;
    int n = pthread_join(tid, &ret);
    std::cout << "thread principal concluída" << " ,n: " << n << "info: " << "," << (char*)ret << std::endl;
    return 0;
}

#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>

class ThreadReturn
{
public:
    ThreadReturn(pthread_t id, const std::string &info, int code)
        : _id(id)
        , _info(info)
        , _code(code)
    {}
public:
    pthread_t _id;	//ID da thread
    std::string _info;	//informações
    int _code;	//código de retorno
};

//conversão para hexadecimal
std::string ToHex(pthread_t tid)
{
    char id[64];
    snprintf(id, sizeof(id), "0x%x", tid);
    return id;
}

//função da thread
void *threadRoutine(void *args)
{
    std::string name = static_cast<const char*>(args);
    int cnt = 3;
    while(cnt--)
    {
        std::cout << "nova thread em execução, nome: " << name << " , ID: " << ToHex(pthread_self()) << std::endl;
        sleep(1);
    }
    ThreadReturn *ret = new ThreadReturn(pthread_self(), "thread encerrada normalmente", 6);
    return ret;
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, threadRoutine, (void*)"thread-1");
    void *ret = nullptr;
    int n = pthread_join(tid, &ret);
    std::cout << "thread principal concluída" << " ,n: " << n << std::endl;
    ThreadReturn *r = static_cast<ThreadReturn *>(ret);
    std::cout << "thread principal recebeu informações da nova thread: " << r-&gt;_info << ", " << r-&gt;_code << ", " << ToHex(r-&gt;_id) << ", " << std::endl;
    delete r;
    return 0;
}

Separando Threads

#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>

int gcnt = 3;

void *ThreadRoutine(void *arg)
{
    pthread_detach(pthread_self());
    const char *threadname = (const char *)arg;
    while(true)
    {
        std::cout<< "Sou uma nova thread" << std::endl;
        gcnt--;
        sleep(1);
    }
}

int main()
{
    pthread_t tid1;
    pthread_create(&tid1, NULL, ThreadRoutine, (void*)"thread 1");
    sleep(1);
    if ( pthread_join(tid1, NULL ) == 0 ) 
    {
      std::cout << "espera pela thread bem-sucedida\n" << std::endl;
    } 
    else 
    {
      std::cout << "falha na espera pela thread\n"<< std::endl;
    }
    int n = pthread_cancel(tid1);
    std::cout << "thread principal cancelou, " << "n: " << n << std::endl;
    return 0;
}

Resultado:

Uma thread separada pode ser cancelada, mas não pode ser esperada com pthread_join.

Resumo

O conteúdo de hoje chegou ao fim. Se encontrar algum erro ou ponto que necessite correção, fique à vontade para nos informar!

Tags: Linux pthread thread control Multithreading pthread_join

Publicado em 9-24 18:02