Junção de threads
Unir um fio significa esperar que ele finalize, o que pode ser visto como um uso específico de variáveis de condição.
Waiting for a thread
Usando o pthread_join subroutine alows um fio a esperar por outro fio a finalizar. Condições mais complexas, como a espera de várias threads para finalizar, podem ser implementadas usando variáveis de condição.
Chamando a subroutine pthread_join
A subroutina pthread_join bloqueia a thread de chamada até que o encadeamento especificado seja finalizado. O fio de destino (o fio cuja finalização é aguardada) não deve ser descolado. Se o encadeamento de destino já estiver finalizado, mas não descolado, a subroutine pthread_join retorna imediatamente. Depois que um encadeamento de destino foi unido, ele é automaticamente descolado, e seu armazenamento pode ser reafirmado.
A tabela a seguir indica os casos possíveis quando uma thread chama a subroutine pthread_join , dependendo do estado e do atributo detachstate do thread de destino.
| Estado de Destino | Alvo desdetetado | Alvo descolado |
|---|---|---|
| O destino ainda está em execução | O caldo está bloqueado até que o alvo seja finalizado. | A chamada retorna imediatamente, indicando um erro. |
| O destino está finalizado | A chamada retorna imediatamente, indicando uma conclusão bem-sucedida. |
Várias joias
Várias threads podem aderir ao mesmo encadeamento de destino, se o destino não for descolado. O sucesso desta operação depende da ordem das chamadas para a subroutine pthread_join e o momento em que o encadeamento de destino finaliza.
- Qualquer chamada para a subroutine pthread_join ocorrendo antes da finalização da thread de destino bloqueia o encadeamento de chamadas.
- Quando o encadeamento de destino finaliza, todas as threads bloqueadas são awoken, e o encadeamento de destino é automaticamente descolado.
- Qualquer chamada para a subroutine pthread_join ocorrendo após a finalização da thread de destino falhará, pois o encadeamento é descolado pela junção anterior.
- Se nenhum fio chamado de subroutine pthread_join antes da finalização da thread de destino, a primeira chamada para a subroutine pthread_join retornará imediatamente, indicando uma conclusão bem-sucedida, e qualquer nova chamada falhará.
Aderir exemplo
#include <pthread.h> /* include file for pthreads - the 1st */
#include <stdio.h> /* include file for printf() */
void *Thread(void *string)
{
int i;
/* writes five messages and exits */
for (i=0; i<5; i++)
printf("%s\n", (char *)string);
pthread_exit(NULL);
}
int main()
{
char *e_str = "Hello!";
char *f_str = "Bonjour !";
pthread_attr_t attr;
pthread_t e_th;
pthread_t f_th;
int rc;
/* creates the right attribute */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,
PTHREAD_CREATE_UNDETACHED);
/* creates both threads */
rc = pthread_create(&e_th, &attr, Thread, (void *)e_str);
if (rc)
exit(-1);
rc = pthread_create(&f_th, &attr, Thread, (void *)f_str);
if (rc)
exit(-1);
pthread_attr_destroy(&attr);
/* joins the threads */
pthread_join(e_th, NULL);
pthread_join(f_th, NULL);
pthread_exit(NULL);
}Um thread não pode se associar a si mesmo porque um deadlock ocorreria e ele é detectado pela biblioteca. No entanto, duas threads podem tentar juntar-se umas às outras. Eles vão deadlock, mas essa situação não é detectada pela biblioteca.
Retornando informações de um encadeamento
A subroutine pthread_join também permite que uma thread retorne informações para outro encadeamento. Quando uma thread chama o subroutine pthread_exit ou quando ele retorna de sua rotina de ponto de entrada, ele retorna um pointer (veja Saindo um Thread). Este ponteiro é armazenado enquanto a thread não for descolada, e a subroutine pthread_join pode retorná-lo.
/* "scanning" thread */
...
buffer = malloc(...);
/* finds the search pattern in the file
and stores the lines in the buffer */
return (buffer);
/* initial thread */
...
for (/* each created thread */) {
void *buf;
pthread_join(thread, &buf);
if (buf != NULL) {
/* print all the lines in the buffer,
preceded by the filename of the thread */
free(buf);
}
}
...Se a thread de destino for cancelada, a sub-rotina pthread_join retornará um valor de -1 convertido em um ponteiro (consulte Cancelamento de uma thread). Como -1 não pode ser um valor de ponteiro, obter -1 como ponteiro retornado de um thread significa que o thread foi cancelado.
O ponteiro retornado pode apontar para qualquer tipo de dado. O ponteiro ainda deve ser válido depois que o fio foi finalizado e seu armazenamento reafirmado. Portanto, evite retornar um valor, pois a rotina do destruidor é chamada quando o armazenamento da thread é reafirmado.
void *returned_data;
...
pthread_join(target_thread, &returned_data);
/* retrieves information from returned_data */
free(returned_data);free(returned_data);/* lock - entering a critical region, no other thread should
run this portion of code concurrently */
if (!flag) {
free(returned_data);
flag = 1;
}
/* unlock - exiting the critical region */O acesso ao bloqueio à região crítica garante que o ponteiro returned_data seja liberado apenas uma vez.
Ao retornar um ponteiro para alocar dinamicamente o armazenamento para várias threads todas executando código diferente, você deve garantir que exatamente um fio libera o ponteiro.