Não preciso finalizar o encadeamento corretamente ou fazê-lo responder a um comando "encerrar". Estou interessado em encerrar o thread com força usando C ++ 11 puro.
Não preciso finalizar o encadeamento corretamente ou fazê-lo responder a um comando "encerrar". Estou interessado em encerrar o thread com força usando C ++ 11 puro.
Respostas:
Você pode ligar std::terminate()
de qualquer segmento e o segmento ao qual você está se referindo terminará com força.
Você pode organizar ~thread()
a execução no objeto do encadeamento de destino, sem interferir join()
nem detach()
nesse objeto. Isso terá o mesmo efeito que a opção 1.
Você pode criar uma exceção que possui um destruidor que lança uma exceção. E, em seguida, organize o encadeamento de destino para lançar essa exceção quando for finalizada com força. A parte complicada dessa questão é conseguir que o thread de destino lance essa exceção.
As opções 1 e 2 não vazam recursos intraprocessos, mas encerram todos os encadeamentos.
A opção 3 provavelmente vazará recursos, mas é parcialmente cooperativa, pois o encadeamento de destino precisa concordar em lançar a exceção.
Não há uma maneira portátil no C ++ 11 (que eu saiba) de matar não cooperativamente um único thread em um programa com vários threads (ou seja, sem matar todos os threads). Não havia motivação para projetar esse recurso.
A std::thread
pode ter esta função de membro:
native_handle_type native_handle();
Você pode usar isso para chamar uma função dependente do SO para fazer o que quiser. Por exemplo, nos sistemas operacionais da Apple, essa função existe e native_handle_type
é a pthread_t
. Se você for bem-sucedido, provavelmente vazará recursos.
std::terminate
nem chama destruidores estáticos nem libera buffers de saída; portanto, a ordem na qual os recursos são liberados não é bem definida, nem você tem garantia de que qualquer dado seja visível ao usuário ou gravado no armazenamento permanente, ou mesmo consistente e completo.
exit()
ou abort()
para o mesmo efeito geral.
A resposta de @Howard Hinnant é correta e abrangente. Mas pode ser mal compreendido se for lido muito rapidamente, porque std::terminate()
(todo o processo) tem o mesmo nome que o "encerramento" que o @AlexanderVX tinha em mente (1 thread).
Resumo: "encerre 1 segmento + com força (o segmento de destino não coopera) + C ++ 11 puro = De jeito nenhum."
std::terminate()
resposta é como uma história clássica de Djinn travessa; cumpre tudo o que o OP deseja, por carta, embora provavelmente não da maneira que ele quis dizer . O humor discreto me fez sorrir. :-)
Esta questão realmente tem uma natureza mais profunda e um bom entendimento dos conceitos de multithreading em geral fornecerá informações sobre este tópico. De fato, não existe nenhum idioma ou sistema operacional que ofereça facilidades para o término abrupto do encadeamento assíncrono sem aviso para não usá-los. E todos esses ambientes de execução aconselham fortemente o desenvolvedor ou mesmo exigem a criação de aplicativos multithreading com base no encerramento de encadeamento cooperativo ou síncrono. A razão para essas decisões e conselhos comuns é que todas elas são construídas com base no mesmo modelo geral de multithreading.
Vamos comparar os conceitos de multiprocessamento e multithreading para entender melhor as vantagens e limitações do segundo.
O multiprocessamento assume a divisão de todo o ambiente de execução em um conjunto de processos completamente isolados, controlados pelo sistema operacional. O processo incorpora e isola o estado do ambiente de execução, incluindo a memória local do processo e os dados dentro dele e todos os recursos do sistema, como arquivos, soquetes, objetos de sincronização. O isolamento é uma característica criticamente importante do processo, porque limita a propagação de falhas pelas bordas do processo. Em outras palavras, nenhum processo pode afetar a consistência de qualquer outro processo no sistema. O mesmo vale para o comportamento do processo, mas da maneira menos restrita e mais desfocada. Nesse ambiente, qualquer processo pode ser morto em qualquer momento "arbitrário", porque primeiro cada processo é isolado;
Por outro lado, o multithreading pressupõe a execução de vários threads no mesmo processo. Mas todos esses threads compartilham a mesma caixa de isolamento e não há nenhum controle do sistema operacional sobre o estado interno do processo. Como resultado, qualquer encadeamento pode alterar o estado do processo global e corrompê-lo. No mesmo momento, os pontos em que o estado do encadeamento é conhecido por ser seguro para eliminar completamente um encadeamento dependem da lógica do aplicativo e não são conhecidos nem pelo sistema operacional nem pelo tempo de execução da linguagem de programação. Como resultado, o término do encadeamento no momento arbitrário significa matá-lo no ponto arbitrário de seu caminho de execução e pode facilmente levar à corrupção de dados em todo o processo, memória e manipular vazamentos,
Devido a isso, a abordagem comum é forçar os desenvolvedores a implementar o término de encadeamento síncrono ou cooperativo, onde um encadeamento pode solicitar outro término de encadeamento e outro encadeamento em ponto bem definido pode verificar essa solicitação e iniciar o procedimento de desligamento a partir do estado bem definido com a liberação de todos os recursos globais do sistema e recursos locais do processo de maneira segura e consistente.
Dicas para usar a função dependente do SO para finalizar o encadeamento C ++:
std::thread::native_handle()
só pode obter o tipo de identificador nativo válido do encadeamento antes de chamar join()
ou detach()
. Depois disso, native_handle()
retorna 0 - pthread_cancel()
irá coredump.
Para chamar efetivamente a função de encerramento de encadeamento nativo (por exemplo pthread_cancel()
), você precisa salvar o identificador nativo antes de chamar std::thread::join()
ou std::thread::detach()
. Para que seu terminador nativo sempre tenha um identificador nativo válido para usar.
Mais explicações, consulte: http://bo-yang.github.io/2017/11/19/cpp-kill-detached-thread .
Eu acho que o segmento que precisa ser eliminado está em qualquer tipo de modo de espera ou está fazendo algum trabalho pesado. Eu sugeriria usar uma maneira "ingênua".
Defina alguns booleanos globais:
std::atomic_bool stop_thread_1 = false;
Coloque o seguinte código (ou similar) em vários pontos-chave, de maneira que faça com que todas as funções na pilha de chamadas retornem até que o encadeamento termine naturalmente:
if (stop_thread_1)
return;
Em seguida, para interromper o encadeamento de outro encadeamento (principal):
stop_thread_1 = true;
thread1.join ();
stop_thread_1 = false; //(for next time. this can be when starting the thread instead)