Multithreading: Finalizar subprocesos en MFC

Hay dos situaciones normales que ocasionan que un subproceso finalice: la función de control se sale o el subproceso no puede ejecutarse hasta su finalización. Si un procesador de texto usa un subproceso para la impresión en segundo plano, la función de control finalizará normalmente si la impresión se completa correctamente. Sin embargo, si el usuario desea cancelar la impresión, el subproceso de impresión en segundo plano debe finalizar prematuramente. En este tema se explica cómo implementar cada situación y cómo obtener el código de salida de un subproceso una vez finalizado.

Finalización normal del subproceso

Para un subproceso de trabajo, la finalización normal del subproceso es sencilla: salga de la función de control y devuelva un valor que indique el motivo de la finalización. Puede usar la función AfxEndThread o una instrucción return. Normalmente, 0 significa una finalización correcta, pero usted debe decidir ello.

Para un subproceso de interfaz de usuario, el proceso es igual de sencillo: desde el subproceso de interfaz de usuario, llame a PostQuitMessage en Windows SDK. El único parámetro que PostQuitMessage toma es el código de salida del subproceso. En cuanto a los subprocesos de trabajo, 0 suele significar la finalización correcta.

Finalización prematura de un subproceso

Finalizar un subproceso prematuramente es casi tan sencillo: llame a AfxEndThread desde el subproceso. Pase el código de salida deseado como único parámetro. Esto detiene la ejecución del subproceso, desasigna la pila del subproceso, desasocia todas las DLL asociadas al subproceso y elimina el objeto del subproceso de la memoria.

Se debe llamar a AfxEndThread desde el subproceso que se finalizará. Si desea finalizar un subproceso de otro subproceso, debe configurar un método de comunicación entre los dos subprocesos.

Recuperar el código de salida de un subproceso

Para obtener el código de salida del subproceso de trabajo o del subproceso de interfaz de usuario, llame a la función GetExitCodeThread. Para información sobre esta función, consulte Windows SDK. Esta función toma el manipulador del subproceso (almacenado en el miembro de datos m_hThread de los objetos CWinThread) y la dirección de un DWORD.

Si el subproceso sigue activo, GetExitCodeThread coloca STILL_ACTIVE en la dirección DWORD proporcionada; de lo contrario, el código de salida se coloca en esta dirección.

La recuperación del código de salida de los objetos CWinThread toma un paso adicional. De forma predeterminada, cuando finaliza un subproceso CWinThread, se elimina el objeto de subproceso. Esto significa que no se puede acceder al miembro de datos m_hThread porque el objeto CWinThread ya no existe. Para evitar esta situación, realice una de las acciones siguientes:

  • Establezca el miembro de datos m_bAutoDelete en FALSE. Esto permite que el objeto CWinThread sobreviva una vez finalizado el subproceso. Puede acceder al miembro de datos m_hThread después de finalizado el subproceso. Sin embargo, si usa esta técnica, es responsable de destruir el objeto CWinThread porque el marco no lo eliminará automáticamente por usted. Este es el método preferido.

  • Almacene el manipulador del subproceso por separado. Una vez creado el subproceso, copie su miembro de datos m_hThread (mediante ::DuplicateHandle) en otra variable y acceda a ella a través de esa variable. De este modo, el objeto se elimina automáticamente cuando se produce la finalización y todavía puede averiguar por qué finalizó el subproceso. Tenga cuidado de que el subproceso no finalice antes de que pueda duplicar el manipulador. La manera más segura de hacerlo es pasar CREATE_SUSPENDED a AfxBeginThread, almacenar el manipulador y, a continuación, reanudar el subproceso mediante una llamada a ResumeThread.

Cualquiera de los métodos permite determinar por qué un objeto CWinThread finalizó.

Consulte también

Multithreading con C++ y MFC
_endthread, _endthreadex
_beginthread, _beginthreadex
ExitThread