Multithread: encerrando threads
Duas situações normais fazem com que um segmento seja finalizado: a função de controle é encerrada ou o segmento não pode ser executado para a conclusão. Se um processador de texto usou um thread para impressão em segundo plano, a função de controle finalizaria normalmente se a impressão fosse concluída com êxito. Se o usuário deseja cancelar a impressão, porém, o thread de impressão em segundo plano tem que ser finalizado prematuramente. Este tópico explica como implementar cada situação e como obter o código de saída de um thread depois que ele é finalizado.
Encerramento Normal de Thread
Terminação prematura de thread
Recuperando o código de saída de um thread
Encerramento Normal de Thread
Para um thread de trabalho, o encerramento normal do thread é simples: saia da função de controle e retorne um valor que signifique a razão para o encerramento. Você pode usar a função AfxEndThread ou uma instrução return. Em geral, 0 significa conclusão com êxito, mas depende da sua configuração.
Para um encadeamento de interface do usuário, o processo é igualmente simples: de dentro do encadeamento de interface do usuário, chame PostQuitMessage no Windows SDK. O único parâmetro que leva PostQuitMessage é o código de saída de thread. Quanto a threads de trabalho, 0 significa normalmente conclusão com êxito.
Terminação prematura de thread
A terminação prematura de um thread é quase simples: chame AfxEndThread de dentro do thread. Passe o código de saída desejado como o único parâmetro. Isso para a execução do thread, desaloca a pilha do thread, dispara todas as DLLs anexadas ao thread e exclui o objeto de thread da memória.
AfxEndThread deve ser chamado de dentro do thread para ser encerrado. Se deseja encerrar um thread a partir de outro thread, você deve configurar um método de comunicação entre os dois threads.
Recuperando o código de saída de um thread
Para obter o código de saída de trabalhador ou o encadeamento de interface do usuário, chame a função GetExitCodeThread . Para obter informações sobre essa função, consulte o Windows SDK. Essa função usa o manipulador para o thread (armazenado no membro de dados m_hThread de objetos CWinThread) e o endereço de DWORD.
Se o segmento ainda está ativo, GetExitCodeThread coloca STILL_ACTIVE no endereço DWORD fornecido; caso contrário, o código de saída é colocado neste endereço.
A recuperação do código de saída do objeto CWinThread usa uma etapa adicional. Por padrão, quando um thread CWinThread finaliza, o objeto de thread é excluído. Isso significa que você não pode acessar o membro de dados m_hThread porque o objeto CWinThread não existe mais. Para evitar esta situação, execute um dos procedimentos a seguir:
Defina o membro de dados m_bAutoDelete como FALSO. Isso permite que o objeto CWinThread sobreviva depois que o segmento tiver sido terminado. Em seguida, é possível acessar o membro de dados m_hThread após a thread ser encerrada. Porém, se usar essa técnica, você será responsável por destruir o objeto CWinThread, porque a estrutura não o excluirá automaticamente. Esse é o método preferido.
Armazene o manipulador do thread separadamente. Depois que o thread é criado, copie seu membro de dados m_hThread (usando ::DuplicateHandle) para outra variável e acesse-o por meio dessa variável. Dessa maneira, o objeto é automaticamente excluído quando a terminação ocorre e você ainda pode descobrir porque o thread foi terminado. Cuidado para o thread não terminar para você poder duplicar o identificador. A maneira mais segura de fazer isso é passar CREATE_SUSPENDED para AfxBeginThread, armazenar o manipulador e então retomar o thread chamando ResumeThread.
Qualquer um desses métodos permite que você determine por que um objeto CWinThread foi finalizado.