Red de conocimiento informático - Material del sitio web - Cómo utilizar AfxBeginThread para crear objetos de subproceso MFC y objetos de subproceso Win32

Cómo utilizar AfxBeginThread para crear objetos de subproceso MFC y objetos de subproceso Win32

1. Pregunta

Escriba un programa de un solo subproceso que requiera mucho tiempo:

Cree una nueva aplicación basada en diálogo SingleThread, en el cuadro de diálogo principal IDD_SINGLETHREAD_DIALOG Agregar un botón con el ID IDC_SLEEP_SIX_SECOND y el título

"Retraso 6 segundos". Agregue la función de respuesta del botón. El código es el siguiente:

void CSingleThreadDlg::OnSleepSixSecond()

{

Sleep(6000); //Retraso 6 segundos

}

Compile y ejecute la aplicación, haga clic en "Retraso 6 segundos" "Segundos", encontrará que durante estos 6 segundos el programa "fallará" y ya no responderá a otros mensajes. Para manejar mejor esta operación que requiere mucho tiempo, necesitamos aprender programación multiproceso.

2. Descripción general de subprocesos múltiples

Los procesos y los subprocesos son conceptos del sistema operativo. Un proceso es una instancia de ejecución de una aplicación. Cada proceso se compone de espacio de direcciones virtuales privadas, código, datos y otros recursos del sistema. Los recursos creados durante el proceso en ejecución finalizarán cuando finalice el proceso. Los recursos del sistema utilizados se liberan o cierran cuando finaliza el proceso.

Un hilo es una unidad de ejecución dentro de un proceso. Después de que el sistema crea un proceso, en realidad inicia el hilo de ejecución principal que ejecuta el proceso. El hilo de ejecución principal proporciona el punto de partida del programa al sistema Windows en forma de una dirección de función, como

<. p>función principal o WinMain. Cuando finaliza el hilo de ejecución principal, el proceso también finaliza.

Cada proceso tiene al menos un hilo de ejecución principal, que no necesita ser creado activamente por el usuario, sino que lo crea automáticamente el sistema. Los usuarios crean otros subprocesos en la aplicación según sea necesario y varios subprocesos se ejecutan simultáneamente en el mismo proceso. Todos los subprocesos de un proceso están en el espacio de direcciones virtuales del proceso y utilizan estos espacios de direcciones virtuales, variables globales y recursos del sistema al mismo tiempo. Por lo tanto, la comunicación entre subprocesos es muy conveniente y la aplicación de tecnología de subprocesos múltiples también es relativamente. extenso.

Múltiples subprocesos pueden lograr un procesamiento paralelo, evitando que una determinada tarea ocupe tiempo de CPU durante mucho tiempo. Una cosa a tener en cuenta es que la mayoría de las computadoras actualmente tienen un solo procesador (CPU). Para ejecutar todos estos subprocesos, el sistema operativo programa algo de tiempo de CPU para cada subproceso independiente. El sistema operativo proporciona intervalos de tiempo a los subprocesos de forma rotativa. . Esto da la ilusión de que todos estos hilos se están ejecutando al mismo tiempo. Se puede ver que si dos subprocesos muy activos compiten por el control de la CPU, consumirán muchos recursos de la CPU al cambiar de subproceso, lo que en realidad reducirá el rendimiento del sistema. Esto debe tenerse en cuenta al realizar programación multiproceso.

Las funciones del SDK de Win32 admiten programación multiproceso y proporcionan diversas operaciones de sincronización, exclusión mutua y secciones críticas en los principios del sistema operativo. En Visual C++ 6.0, la programación multiproceso también se implementa utilizando la biblioteca de clases MFC, lo que hace que la programación multiproceso sea más conveniente.

3. La API de Win32 admite programación multiproceso

Win32 proporciona una serie de funciones API para completar la creación, suspensión, recuperación, terminación y comunicación de subprocesos. Algunas de las funciones importantes se seleccionarán para su descripción a continuación.

1. HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,

DWORD dwStackSize,

LPTHREAD_START_ROUTINE lpStartAddress,

LPVOID lpParameter,

DWORD dwCreationFlags,

LPDWORD lpThreadId);

Esta función crea un nuevo hilo en el espacio de proceso del proceso que llama y devuelve el identificador del hilo creado, con cada parámetro El la descripción es la siguiente:

lpThreadAttributes: un puntero a una estructura SECURITY_ATTRIBUTES, que determina los atributos de seguridad del hilo y generalmente se establece en NULL

dwStackSize: especifica la profundidad de la pila de; el hilo, generalmente Todos se establecen en 0;

lpStartAddress: indica la dirección de la función donde se encuentra el código cuando el nuevo hilo comienza a ejecutarse, es decir, la dirección inicial del hilo. La situación general es (LPTHREAD_START_ROUTINE) ThreadFunc,

ThreadFunc

es el nombre de la función del hilo

lpParameter: especifica el parámetro de 32 bits transmitido al; hilo cuando se ejecuta el hilo. Es decir, los parámetros de la función del hilo;

dwCreationFlags: indicadores adicionales que controlan la creación del hilo, que pueden tomar dos valores. Si este parámetro es 0, el hilo comenzará a ejecutarse inmediatamente después de su creación; si este parámetro es CREATE_SUSPENDED, después de que el sistema genere el hilo, el hilo estará en un estado suspendido y no se ejecutará inmediatamente hasta que se llame a la función ResumeThread;

lpThreadId: Este parámetro devuelve el ID del hilo creado;

Si la creación es exitosa, se devuelve el identificador del hilo; de lo contrario, se devuelve NULL.

2. DWORD SuspendThread(HANDLE hThread);

Esta función se utiliza para suspender el hilo especificado. Si la función se ejecuta con éxito, la ejecución del hilo finaliza. 3. DWORD ResumeThread(HANDLE hThread);

Esta función se utiliza para finalizar el estado suspendido del hilo y ejecutar el hilo.

4. VOID ExitThread(DWORD dwExitCode);

Esta función se utiliza para finalizar la ejecución del hilo y se llama principalmente en la función de ejecución del hilo. El parámetro dwExitCode se utiliza para establecer el código de salida del hilo.

5. BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);

Generalmente, una vez finalizado el hilo, la función del hilo regresa normalmente, pero la aplicación puede llamar a TerminateThread para terminar por la fuerza un determinado hilo. hilo. ejecución del hilo. El significado de cada parámetro es el siguiente:

hThread: el identificador del hilo que se va a terminar;

dwExitCode: se utiliza para especificar el código de salida del hilo.

Usar TerminateThread() para finalizar la ejecución de un subproceso no es seguro y puede causar inestabilidad en el sistema; aunque esta función finaliza inmediatamente la ejecución del subproceso, no libera los recursos ocupados por el subproceso. Por lo tanto, generalmente no se recomienda utilizar esta función.

6. BOOL PostThreadMessage(DWORD idThread,

UINT Msg,

WPARAM wParam,

LPARAM lParam);

Esta función coloca un mensaje en la cola de mensajes del hilo especificado y regresa sin esperar a que el hilo procese el mensaje.

idThread: ID del hilo que recibirá el mensaje

Msg: especifica el mensaje utilizado para enviar

wParam: parámetro de palabra relacionado con el mensaje; ;

lParam: parámetro largo relacionado con el mensaje;

Al llamar a esta función, si el hilo que está a punto de recibir el mensaje no crea un bucle de mensajes, la función fallará. para ejecutar.

4. Rutinas de programación multiproceso API Win32

Rutina 1 MultiThread1

Cree un proyecto basado en diálogo MultiThread1 y agregue dos elementos al cuadro de diálogo IDD_MULTITHREAD1_DIALOG. Un botón y un cuadro de edición. Los ID de los dos botones son IDC_START e IDC_STOP. Los títulos son "Inicio" y "Detener" respectivamente. El atributo de IDC_STOP está seleccionado como Deshabilitado; El cuadro de edición es IDC_TIME. El atributo Seleccionar Sólo lectura;

Agregue la declaración de función de subproceso en el archivo MultiThread1Dlg.h: void ThreadFunc();

. Tenga en cuenta que la declaración de la función del subproceso debe estar en Externo a la clase CMultiThread1Dlg. Agregue variables protegidas dentro de la clase CMultiThread1Dlg: HANDLE

hThread;

DWORD ThreadID;

representan el identificador y el ID del hilo respectivamente.

 

Agregue la variable global m_bRun en el archivo MultiThread1Dlg.cpp: volátil BOOL m_bRun;

m_bRun representa si el hilo se está ejecutando.

Debe tener en cuenta que la variable global m_bRun utiliza el modificador volátil. La función del modificador volátil

es decirle al compilador que no es necesario realizar ninguna optimización en la variable. , es decir, no es necesario convertirlo en un registro y el valor se puede cambiar externamente. Para variables globales a las que hacen referencia varios subprocesos, volátil

es un modificador muy importante.

Escribe la función del hilo: void ThreadFunc()

{

CTime time;

CString strTime;

m_bRun=TRUE;

mientras(m_bRun)

{

tiempo=CTime::GetCurrentTime();

strTime=tiempo Formato("%H:%M:%S");

::SetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_TIME,strTime);

Sueño(1000);

}

}

Esta función de hilo no tiene parámetros y no devuelve un valor de función. Mientras m_bRun sea TRUE, el hilo seguirá ejecutándose.

Haga doble clic en el botón IDC_START para completar la función de mensaje del botón:

void CMultiThread1Dlg::OnStart()

{

// TODO: agregue aquí el código del controlador de notificaciones de control

hThread=CreateThread(NULL,

0,

(LPTHREAD_START_ROUTINE)ThreadFunc,

NULL,

0,

&ThreadID);

GetDlgItem(IDC_START)->EnableWindow(FALSE);

GetDlgItem (IDC_STOP)- >EnableWindow(TRUE);

}

Haga doble clic en el botón IDC_STOP para completar la función de mensaje del botón: void CMultiThread1Dlg::OnStop()

{

// TODO: agregue aquí el código del controlador de notificaciones de control

m_bRun=FALSE;

GetDlgItem(IDC_START)->EnableWindow(TRUE );

GetDlgItem(IDC_STOP)->EnableWindow(FALSE);

}

Compile y ejecute esta rutina para experimentar subprocesos múltiples escritos utilizando la API de Win32.

Rutina 2 MultiThread2

Este hilo demuestra cómo transferir un parámetro entero a un hilo y cómo esperar a que un hilo complete el procesamiento.

Cree un proyecto MultiThread2 basado en diálogo, agregue un cuadro de edición y un botón al cuadro de diálogo IDD_MULTITHREAD2_DIALOG, los ID son IDC_COUNT, IDC_START

y el título del control del botón es "Start" ";

Agregue la declaración de función de subproceso en el archivo MultiThread2Dlg.h: void ThreadFunc(int integer);

Tenga en cuenta que la declaración de función de subproceso debe estar fuera de la clase CMultiThread2Dlg .

Agregar variables protegidas dentro de la clase CMultiThread2Dlg: HANDLE hThread;

DWORD ThreadID;

Representa el identificador y el ID del hilo respectivamente.

 

Abra ClassWizard y agregue la variable de tipo int m_nCount al cuadro de edición IDC_COUNT.

Agregue el archivo MultiThread2Dlg.cpp: void

ThreadFunc(int integer)

{

int i;

for(i= 0;i

{

Bip(200,50);

Dormir(1000);

}

}

Haga doble clic en el botón IDC_START para completar la función de mensaje del botón: void CMultiThread2Dlg::OnStart()

{

UpdateData( TRUE);

int integer=m_nCount;

hThread=CreateThread(NULL,

0,

(LPTHREAD_START_ROUTINE )ThreadFunc,

(VOID*)entero,

0,

&ThreadID);

GetDlgItem(IDC_START)->EnableWindow( FALSE);

WaitForSingleObject(hThread,INFINITE);

GetDlgItem(IDC_START)->EnableWindow(TRUE);

}

Por cierto, función WaitForSingleObject, su prototipo de función es: DWORD WaitForSingleObject(HANDLE hHandle,DWORD

dwMillisegundos);

hHandle es el identificador del objeto a monitorear (generalmente una sincronización objeto o un subproceso);

dwMillisegundos es el valor de tiempo de espera establecido por el objeto hHandle, en milisegundos;

Cuando se llama a esta función en un subproceso, el subproceso se bloquea temporalmente y el sistema monitorea el punto señalado por hHandle El estado del objeto. Si dentro de los milisegundos de dwMillisegundos suspendidos, se señala el objeto que el subproceso está esperando, la función regresa inmediatamente; si el tiempo de espera ha alcanzado los milisegundos de dwMillisegundos, pero el objeto señalado por hHandle aún no ha cambiado. Si hay un estado de señal, el función

aún regresará. El parámetro dwMillisegundos tiene dos valores con significado especial: 0 e INFINITO. Si es 0, la función regresa inmediatamente; si es INFINITO, el hilo se suspende hasta que se señalice el objeto señalado por hHandle.

El propósito de esta rutina que llama a esta función es esperar hasta que el hilo regrese después de presionar el botón IDC_START y luego restaurar el estado normal del botón IDC_START. Compile y ejecute esta rutina y experimentela cuidadosamente.

Rutina 3 MultiThread3

También es posible pasar una estructura a una función de hilo pasando un parámetro de puntero que apunte a la estructura.

Primero defina una estructura:

typedef struct

{

int firstArgu,

long secondArgu,

}myType,*pMyType;

Al crear un hilo, CreateThread(NULL,0,threadFunc,pMyType,…);

Dentro de la función threadFunc, puedes usar "cast":

int intValue=((pMyType)lpvoid)->firstArgu;

long longValue=((pMyType)lpvoid)-> seconddArgu;

...

Ejemplo 3 MultiThread3 demostrará cómo pasar un parámetro de puntero que apunta a una estructura.

Cree un proyecto MultiThread3 basado en diálogo, agregue un cuadro de edición IDC_MILLISECOND, un botón IDC_START y el título

para "Iniciar" en el cuadro de diálogo IDD_MULTITHREAD3_DIALOG.

, una barra de progreso IDC_PROGRESS1;

Abra ClassWizard, agregue la variable de tipo int m_nMilliSecond al cuadro de edición IDC_MILLISECOND, agregue la variable de tipo CProgressCtrl a la barra de progreso IDC_PROGRESS1

m_ctrlProgress;

Agregue una definición de estructura al archivo MultiThread3Dlg.h: struct threadInfo

{

UINT nMilliSecond;

CProgressCtrl* pctrlProgress;

};

Declaración de función de subproceso: UINT ThreadFunc(LPVOID lpParam);

Tenga en cuenta que ambos deben estar fuera de la clase CMultiThread3Dlg.

Agregar variables protegidas dentro de la clase CMultiThread3Dlg: HANDLE hThread;

DWORD ThreadID;

Representa el identificador y el ID del hilo respectivamente.

Realice las siguientes operaciones en el archivo MultiThread3Dlg.cpp:

Defina la variable pública threadInfo Info;

Haga doble clic en el botón IDC_START y agregue el mensaje correspondiente. función de procesamiento: void CMultiThread3Dlg::OnStart()

{

// TODO: agregue aquí el código del controlador de notificación de control

UpdateData(TRUE);

Info.nMilliSecond=m_nMilliSecond;

Info.pctrlProgress=&m_ctrlProgress;

hThread=CreateThread(NULL,

0,

(LPTHREAD_START_ROUTINE)ThreadFunc,

&Info,

0,

&ThreadID);

}

En función Agregar declaración a BOOL CMultiThread3Dlg::OnInitDialog(): {

// TODO: Agregar inicialización adicional aquí

m_ctrlProgress.SetRange( 0,99 );

m_nMilliSecond=10;

UpdateData(FALSE);

return TRUE; // devuelve TRUE a menos que establezcas el foco en un control.

}

Agregar función de procesamiento de subprocesos: UINT ThreadFunc(LPVOID lpParam) {

threadInfo* pInfo=(threadInfo*)lpParam;

for( int i=0;i<100;i++)

{

int nTemp=pInfo->nMilliSecond;

pInfo->pctrlProgress-> SetPos(i );

Sleep(nTemp);

}

devuelve 0;

}

Por cierto, simplemente agregue algo, si agrega declaraciones en la función void CMultiThread3Dlg::OnStart(), encontrará que la barra de progreso no se actualiza y el hilo principal deja de responder después de compilar y ejecutar. ¿Cuál es la razón? Esto se debe a que la función WaitForSingleObject espera a que finalice el hilo secundario

(ThreadFunc), lo que provoca un punto muerto en el hilo. Porque la función WaitForSingleObject suspenderá el hilo principal (no se procesará ningún mensaje) y el hilo secundario ThreadFunc está configurando la barra de progreso y esperando que el hilo principal regrese después de procesar el mensaje de actualización antes de detectarlo. De esta manera, ambos subprocesos se esperan el uno al otro y se produce un punto muerto. Debes prestar atención para evitar esto al programar.

Rutina 4 MultiThread4

Esta rutina prueba el número máximo. de hilos que se pueden crear en Windows.

Cree un proyecto MultiThread4 basado en diálogo, agregue un botón IDC_TEST y un cuadro de edición IDC_COUNT al cuadro de diálogo IDD_MULTITHREAD4_DIALOG, y el título del botón es

"Prueba"

, Seleccione Sólo lectura para la propiedad del cuadro de edición;

Realice las siguientes operaciones en el archivo MultiThread4Dlg.cpp:

Agregue la variable pública volátil BOOL m_bRunFlag=TRUE;

Esta variable indica si se pueden seguir creando subprocesos.

Añadir función de subproceso:

DWORD WINAPI threadFunc(LPVOID threadNum)

{

while(m_bRunFlag)

{

Dormir(3000);

}

devuelve 0;

}

Mientras la variable m_bRunFlag Si es VERDADERO, el hilo sigue ejecutándose.

Haga doble clic en el botón IDC_TEST y agregue su función de mensaje de respuesta: void CMultiThread4Dlg::OnTest()

{

DWORD threadID;

GetDlgItem (IDC_TEST)->EnableWindow(FALSE);

long nCount=0;

while(m_bRunFlag)

{

if( CreateThread(NULL,0,threadFunc,NULL,0,&threadID)==NULL)

{

m_bRunFlag=FALSE;

break;

}

else

{

nCount++;

}

}

//Crear hilos continuamente hasta que no se puedan crear más

m_nCount=nCount;

UpdateData(FALSE);

Sleep(5000) ;

p>

//Retraso de 5 segundos, esperando a que finalicen todos los hilos creados

GetDlgItem(IDC_TEST)->EnableWindow(TRUE);

m_bRunFlag =VERDADERO;

}

5. Compatibilidad de MFC con programación multiproceso

Hay dos tipos de subprocesos en MFC, que se denominan subprocesos de trabajo y de usuario. hilos de interfaz. La principal diferencia entre los dos es que el hilo de trabajo no tiene un bucle de mensajes, mientras que el hilo de la interfaz de usuario tiene su propia cola de mensajes y su propio bucle de mensajes.

Los hilos de trabajo no tienen mecanismo de mensajes y generalmente se utilizan para realizar cálculos en segundo plano y tareas de mantenimiento, como procesos de cálculo prolongados, impresión en segundo plano de impresoras, etc. El subproceso de la interfaz de usuario se utiliza generalmente para procesar la entrada del usuario independientemente de la ejecución de otros subprocesos, responder a eventos y mensajes generados por el usuario y el sistema, etc. Pero para la programación API de Win32, no hay diferencia entre estos dos subprocesos. Todos solo necesitan la dirección de inicio del subproceso para iniciar el subproceso y realizar tareas.

En MFC, la función global AfxBeginThread() se usa generalmente para crear e inicializar la ejecución de un hilo. Esta función tiene dos formas sobrecargadas, que se usan para crear hilos de trabajo e interfaces de usuario.

Hilos enfrentados.

Los prototipos y parámetros de las dos funciones sobrecargadas se describen a continuación:

(1) CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc,

LPVOID pParam,

nPriority= THREAD_PRIORITY_NORMAL,

UINT nStackSize=0,

DWORD dwCreateFlags=0,

LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);

PfnThreadProc: apunta a el hilo de trabajo El puntero a la función de ejecución, el prototipo de la función de hilo debe declararse de la siguiente manera: UINT ExecutingFunction(LPVOID

pParam);

Tenga en cuenta que ExecutingFunction() debe devolver un Valor de tipo UINT para Especifica el motivo por el cual finaliza la función. Generalmente, devolver 0 indica una ejecución exitosa.

pParam: Un parámetro de 32 bits pasado a la función del subproceso. La función en ejecución interpretará el valor de alguna manera. Puede ser un valor numérico, o un puntero a una estructura, o incluso puede ignorarse;

nPrioridad: la prioridad del hilo. Si es 0, el hilo tiene la misma prioridad que su hilo padre;

nStackSize: el tamaño de la pila que el hilo se asigna a sí mismo, en bytes. Si nStackSize se establece en 0, la pila del subproceso se establece en el mismo tamaño que la pila del subproceso principal;

dwCreateFlags: si es 0, el subproceso comienza a ejecutarse inmediatamente después de la creación. Si es CREATE_SUSPEND, el hilo se suspende inmediatamente después de la creación;

lpSecurityAttrs: el puntero de atributo de seguridad del hilo, generalmente NULL;

(2) CWinThread* AfxBeginThread(CRuntimeClass* pThreadClass ,

int nPriority=THREAD_PRIORITY_NORMAL,

UINT nStackSize=0,

DWORD dwCreateFlags=0,

LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);

pThreadClass es un puntero al objeto de clase de tiempo de ejecución de una clase exportada de CWinThread

La clase exportada define el inicio y la salida del hilo de la interfaz de usuario creado y otros parámetros. Lo mismo que el formulario 1. El hilo generado usando este prototipo de función también tiene un mecanismo de mensaje. En ejemplos futuros, encontraremos que es casi el mismo que el mecanismo del hilo principal.

Aquí damos una breve descripción de los miembros de datos y funciones comunes de la clase CWinThread.

m_hThread: identificador del hilo actual

m_nThreadID: ID del hilo actual

m_pMainWnd: puntero a la ventana principal de la aplicación

BOOL CWinThread::CreateThread(DWORD dwCreateFlags=0,

UINT nStackSize=0,

LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);

dwCreateFlags en este función, Los parámetros nStackSize y lpSecurityAttrs tienen el mismo significado que los parámetros correspondientes en la función API CreateThread. La función se ejecuta con éxito y devuelve un valor distinto de cero; de lo contrario, devuelve 0.

Generalmente, se llama a AfxBeginThread() para crear e iniciar un hilo una vez, pero también puedes crear un hilo mediante un método de dos pasos: primero crea un objeto de la clase CWinThread

y luego llame a la función miembro CreateThread() del objeto para iniciar el hilo.

virtual BOOL CWinThread::InitInstance();

Sobrecarga esta función para controlar la inicialización de la instancia del hilo de la interfaz de usuario. Si la inicialización es exitosa, se devuelve un valor distinto de cero; de lo contrario, se devuelve 0. Los subprocesos de la interfaz de usuario a menudo sobrecargan esta función y los subprocesos de trabajo generalmente no usan InitInstance().

virtual int CWinThread::ExitInstance();

Vuelva a cargar esta función para realizar algunos trabajos de limpieza necesarios antes de que finalice el hilo. Esta función devuelve el código de salida del hilo, 0 indica una ejecución exitosa y se utilizan valores distintos de cero para identificar varios errores. Al igual que la función miembro

InitInstance(), esta función solo se aplica al hilo de la interfaz de usuario.

6. Ejemplos de programación multiproceso MFC

En el entorno de programación Visual C++

6.0, no solo podemos escribir aplicaciones Win32 de 32 bits estilo C. , pero también puede utilizar la biblioteca de clases MFC para escribir aplicaciones estilo C++, cada una con sus propias ventajas y desventajas.

Las aplicaciones basadas en Win32 tienen códigos de ejecución pequeños y una alta eficiencia de ejecución, pero requieren que los programadores escriban más códigos y administren todos los recursos proporcionados por el sistema al programa, mientras que las aplicaciones basadas en bibliotecas de clases MFC pueden hacerlo

Cree aplicaciones rápidamente. La biblioteca de clases proporciona a los programadores una gran cantidad de clases encapsuladas, y Developer

Studio proporciona a los programadores algunas herramientas para administrar los programas fuente del usuario. Sus deficiencias El código de la biblioteca de clases es. muy grande. Debido a las ventajas de usar bibliotecas de clases, como velocidad, simplicidad y funciones potentes, Visual

C++ recomienda usar bibliotecas de clases MFC para el desarrollo de programas a menos que existan necesidades especiales.

Sabemos que hay dos tipos de subprocesos en MFC: subprocesos de interfaz de usuario y subprocesos de trabajo. Ilustraremos cada uno con ejemplos.

Utilice la programación de la biblioteca de clases MFC para implementar subprocesos de trabajo