¿Como realizar muchas tareas pesadas en un programa monohilo?

Iniciado por Filantropo, 19 Mayo 2019, 03:22 AM

0 Miembros y 1 Visitante están viendo este tema.

Filantropo

Hola a todos  :rolleyes:
Tenia curiosidad por saber como hacian sus sources los antiguos desarrolladores de aplicaciones windows cuando una aplicacion debia hacer mas de una tarea pesada usando un solo hilo, como evitaban que se congele la interfaz grafica mientras el hilo hacia trabajo fuerte.

RayR

La forma de hacerlo era, y es, simplemente asegurarse de forma manual que, en medio de las tareas pesadas, los eventos se están procesando de manera periódica. Digamos que tenemos una función que consiste en un bucle con instrucciones complejas, que se repite un número grande de veces (por ejemplo, aplicar un filtro a cada píxel de una imagen). Haciendo algo como esto:

for (i = 0; i < NUMERO_MUY_GRANDE; i++) {
    /* Operaciones costosas
     * ...
     */
    if (hay_mensajes())
        procesa_mensajes();
}


Se logra que, en cada repetición, se efectúe una pequeña parte de los cálculos y luego se verifique si hay mensajes de ventana (por ejemplo, el usuario presionó un botón) y, de ser así, procesarlos. De esa manera el tiempo se reparte entre el manejo de la GUI y las tareas complejas del programa.

Filantropo

#2
Y eso¿ como se haria?
, suele haber un bucle while con un getmessage que recoge los mensajes y pues si vetifica mensajes en medio de la tarea pesada estaria entrando de nuevo al bucle y pues solo con postquitmessage se puede salir del bucle pero tambien cerraria toda la aplicacion ¿como se haria para salir y continuar con la tarea pesada?

Otra cosa.
Que pasaria si al verificar hubiese un mensaje del mismo botton que  provoco la tarea pesada, haria q se ejecute la tarea pesada de nuevo   sin haber terminado la primera??



RayR

Pues como te lo puse. Las funciones reales serían:
/* PeekMessage para no bloquear la ejecucion si no hay mensajes */
if (PeekMessage(...)) {
    TranslateMessage(...);
    DispatchMessage(...);
/* Aqui retornamos justo despues de procesar el mensaje */
}

Ahora, cierto que en las aplicaciones de Windows tenemos un bucle principal de eventos, normalmente con GetMessage, pero no sé por qué piensas que estaríamos entrando de nuevo en él. Aquí lo que hacemos es simplemente verificar la cola de mensajes, y si hay alguno, DispatchMessage se encargaría de que se invoque nuestro procedimiento de ventana (no el bucle principal, que me parece que es tu confusión), y lo procese, y luego retornamos a donde te puse, a seguir con la tarea pesada.

En cuanto a lo otro, eso depende del programa. Algo común es que, una vez que se presiona un botón para una acción así, éste se deshabilite para evitar múltiples pulsaciones, y sólo se habilite de nuevo una vez finalizada la tarea. Alternativamente, algunos programas hacen que el mismo botón sirva para iniciar la ejecución de la tarea, y para cancelarla. Si se presiona mientras ya se está ejecutando la tarea, provocaría que sea cancelada.

Filantropo

Hola, gracias bro, la verdad no sabia como hacer para que un solo hilo se encargue de hacer todo el trabajo y es que solo encontre ejemplos que se usaban hilos adicionales para el trabajo pesado y el principal dedicado al GUI, en otros lenguajes como vb6 que no dejan crear hilos pues la GUI se congela en los trabajos pesado, de ahi la curiosidad de saber como hacian las antiguas apps para evitar ese problema  de congelarse que lenguajes como vb6 que son mas recientes no pueden resolver.

Lo de entrar a verificar mensajes : no sabia de peekmessage, lo confundi con volver a entrar al bucle del getmessage  (winproc llamando a winmain  :xD )
Lo de habilitar controles, encontre EnableWindow para esa tarea.

Gracias lo entendi.  ;D


Podrias de favor compartir si tuvieras la url donde tratan esos temas?

RayR

#5
Sí, eso podía ser también un problema en VB6, aunque para eso hay una función, DoEvents, que hace más o menos lo mismo que el código que puse. La pones en medio de una tarea pesada y se encargará de que se verifiquen y procesen mensajes.

Y sí, con EnableWindow lo puedes hacer.

Yo en realidad esto lo fui aprendiendo más que nada con la documentación de Microsoft.

Hay también aquí algo de información aquí: http://winapi.conclase.net pero es más bien básica. Realmente la documentación oficial es a donde hay que recurrir para profundizar en estos temas.