Em algum momento eu tenho que usar std::thread
para acelerar meu aplicativo. Eu também sei join()
espera até que um segmento seja concluído. Isso é fácil de entender, mas qual é a diferença entre ligar detach()
e não ligar?
Eu pensei que detach()
, sem , o método do thread funcionará usando um thread de forma independente.
Não desanexando:
void Someclass::Somefunction() {
//...
std::thread t([ ] {
printf("thread called without detach");
});
//some code here
}
Ligando com desanexação:
void Someclass::Somefunction() {
//...
std::thread t([ ] {
printf("thread called with detach");
});
t.detach();
//some code here
}
std
eboost
tópicos têmdetach
ejoin
modelados de perto depois de threads POSIX.Respostas:
No destruidor de
std::thread
,std::terminate
é chamado se:t.join()
)t.detach()
)Portanto, você sempre deve ter um
join
oudetach
um encadeamento antes que os fluxos de execução cheguem ao destruidor.Quando um programa termina (ou seja,
main
retorna), os demais segmentos desanexados em execução em segundo plano não são esperados; em vez disso, sua execução é suspensa e seus objetos locais de thread destruídos.Fundamentalmente, isso significa que a pilha desses threads não é desenrolada e, portanto, alguns destruidores não são executados. Dependendo das ações que esses destruidores deveriam empreender, essa poderia ser uma situação tão ruim como se o programa tivesse travado ou tivesse sido morto. Esperamos que o sistema operacional libere os bloqueios nos arquivos, etc ... mas você pode ter corrompido a memória compartilhada, os arquivos semi-escritos e similares.
Então, você deve usar
join
oudetach
?join
detach
fonte
Você deve ligar
detach
se não quiser esperar que o encadeamento seja concluído,join
mas o encadeamento continuará sendo executado até que esteja pronto e será encerrado sem que o encadeamento principal o aguarde especificamente.detach
basicamente liberará os recursos necessários para poder implementarjoin
.É um erro fatal se um objeto de encadeamento termina sua vida e nem
join
nemdetach
foi chamado; neste casoterminate
é invocado.fonte
Quando você desanexa o encadeamento, significa que você não precisa fazer
join()
isso antes de sairmain()
.A biblioteca de encadeamentos realmente aguardará cada um desses encadeamentos abaixo do principal , mas você não deve se preocupar com isso.
detach()
é útil principalmente quando você tem uma tarefa que precisa ser executada em segundo plano, mas não se importa com a execução. Geralmente, esse é o caso de algumas bibliotecas. Eles podem criar silenciosamente um thread de trabalho em segundo plano e desanexá-lo para que você nem perceba.fonte
Esta resposta visa responder à pergunta no título, em vez de explicar a diferença entre
join
edetach
. Então, quando devestd::thread::detach
ser usado?No código C ++ mantido adequadamente
std::thread::detach
, não deve ser usado. O programador deve garantir que todos os threads criados saiam normalmente, liberando todos os recursos adquiridos e executando outras ações de limpeza necessárias. Isso implica que renunciar à propriedade dos encadeamentos invocandodetach
não é uma opção e, portanto,join
deve ser usado em todos os cenários.No entanto, alguns aplicativos contam com APIs antigas e muitas vezes mal projetadas e suportadas, que podem conter funções de bloqueio indefinidamente. Mover invocações dessas funções para um thread dedicado para evitar o bloqueio de outras coisas é uma prática comum. Não há como fazer com que esse encadeamento saia normalmente, portanto, o uso de
join
apenas levará ao bloqueio do encadeamento primário. Essa é uma situação em que o usodetach
seria uma alternativa menos ruim para, por exemplo, alocar umthread
objeto com duração de armazenamento dinâmico e vazá-lo de propósito.fonte
De acordo com cppreference.com :
Por exemplo:
Observe a variável local:
my_thread
enquanto o tempo de vida útilmy_thread
terminar, o destruidor destd::thread
será chamado estd::terminate()
será chamado dentro do destruidor.Mas se você usar
detach()
, não deverámy_thread
mais usá-lo , mesmo que a vida útilmy_thread
tenha acabado, nada acontecerá com o novo encadeamento.fonte
&
na captura lambda, estará usando as variáveis do escopo anexado por referência - para garantir que o tempo de vida de qualquer referência que você refira seja maior que o tempo de vida do encadeamento.