Multithreading: como terminar threads no MFC

Duas situações normais fazem com que um thread seja encerrado: a função de controle é encerrada ou o thread não tem permissão para ser executado até a conclusão. Se um processador de palavras usasse um thread para impressão em segundo plano, a função de controle terminaria normalmente se a impressão fosse concluída com êxito. No entanto, se o usuário quisesse cancelar a impressão, o thread de impressão em segundo plano precisaria ser encerrado prematuramente. Este tópico explica como implementar cada situação e como obter o código de saída de um thread após o término.

Término normal do thread

Para um thread de trabalho, a terminação de thread normal é simples: saia da função de controle e retorne um valor que significa o motivo da rescisão. Você pode usar a função AfxEndThread ou uma instrução return. Normalmente, 0 significa conclusão bem-sucedida, mas isso cabe a você.

Para um thread de interface do usuário, o processo é tão simples quanto: dentro do thread de interface do usuário, chame PostQuitMessage no SDK do Windows. O único parâmetro que PostQuitMessage usa é o código de saída do thread. Quanto aos threads de trabalho, 0 normalmente significa conclusão bem-sucedida.

Término prematuro do thread

Encerrar um thread prematuramente é quase tão simples quanto: chame AfxEndThread de dentro do thread. Passe o código de saída desejado como o único parâmetro. Isso interrompe a execução do thread, desaloca a pilha do thread, desanexa todas as DLLs anexadas ao thread e exclui o objeto thread da memória.

AfxEndThread deve ser chamado de dentro do thread a ser encerrado. Se você quiser encerrar um thread de outro thread, deverá configurar um método de comunicação entre os dois threads.

Recuperando o código de saída de um thread

Para o código de saída do trabalho ou do thread da interface do usuário, chame a função GetExitCodeThread. Para informações sobre essa função, confira o SDK do Windows. Essa função usa o manipulador para o thread (armazenado no membro de dados m_hThread de objetos CWinThread) e o endereço de um DWORD.

Se o thread ainda estiver ativo, GetExitCodeThread colocará STILL_ACTIVE no endereço DWORD fornecido; caso contrário, o código de saída será colocado neste endereço.

Recuperar o código de saída de objetos CWinThread realiza uma etapa extra. Por padrão, quando um thread CWinThread termina, o objeto 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 essa situação, siga um destes procedimentos:

  • Defina o membro de dados m_bAutoDelete como FALSE. Isso permite que o objeto CWinThread sobreviva após o término do thread. Você então pode acessar o membro de dados m_hThread depois que o thread for encerrado. No entanto, se você usar essa técnica, será responsável por destruir o objeto CWinThread porque a estrutura não o excluirá automaticamente para você. Este é o método preferencial.

  • Armazene o identificador do thread separadamente. Depois que o thread for criado, copie seu membro de dados m_hThread (usando ::DuplicateHandle) para outra variável e acesse-o por meio dessa variável. Dessa forma, o objeto é excluído automaticamente quando o encerramento ocorre e você ainda pode descobrir por que o thread foi encerrado. Tenha cuidado para que o thread não seja encerrado antes que você possa duplicar o identificador. A maneira mais segura de fazer isso é passar CREATE_SUSPENDED para AfxBeginThread, armazenar o identificador e retomar o thread chamando ResumeThread.

Qualquer um dos métodos permite determinar por que um objeto CWinThread foi encerrado.

Confira também

Multithreading com C++ e MFC
_endthread, _endthreadex
_beginthread, _beginthreadex
ExitThread