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:
- Retornar diretamente da função da thread. Esta opção não se aplica à thread principal, pois retronar de
mainé equivalente a chamarexit. - A thread pode chamar
pthread_exitpara terminar-se. - Uma thread pode usar
pthread_cancelpara encerrar outra thread no mesmo prcoesso. Usarexit()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:
- Se a thread termina com
return, o valor apontado porvalue_ptrcontém o valor de retorno da função da thread. - Se a thread foi cancelada com
pthread_cancel, o valor apontado éPTHREAD_CANCELED. - Se a thread chama
pthread_exit, o valor apontado contém o argumento passado parapthread_exit. - Se não se deseja informações sobre o estado de término, pode-se passar
NULLcomovalue_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->_info << ", " << r->_code << ", " << ToHex(r->_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!