Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: Miseryk en 7 Mayo 2022, 15:12 pm



Título: C++ Challenge
Publicado por: Miseryk en 7 Mayo 2022, 15:12 pm
Buenas a todos,

tengo un challenge o problema, que realmente me gustaría saber que piensan al respecto o de que manera podrían resolverlo para tener todos los punto de vista posible.

Intro:
Hacer una dll que tenga 3 funciones, para procesar comandos (tipo los que se usan por cmd)

Inicializar() - inicializa todos los recursos en la dll

Apagar() - libera los recursos en la dll (de manera limpia) y termina todos los comandos que están corriendo.

Analizar() - se llama cada tanto (puede variar entre 50ms y 150ms) para procesar las cosas dentro de la dll

A todo ésto hay que definir e implementar una interfaz para la funcionalidad del "Procesador de Comandos", que debe cumplir con:

  • El usuario debe poder llamar a una función para pasarle el comando, como por ej: "comando argumento1 argumento2 ..."
  • El usuario debe proveer un único callback estático para el "Procesador de Comandos" el cual sirve para devolver la salida (en string) de los comandos ejecutados
  • El usuario debe poder proporcionar algunos datos de contexto arbitrarios a la función de entrada cuando ingresa su comando. Cuando se procesa el comando y se emite la salida, este contexto debe devolverse(output) a través del callback además de la cadena de salida.
  • Los comandos solamente son procesados en respuesta a la llamada de la función Analizar(), el usuario puede brindar varios comandos antes de llamar a esta función, en este caso,estos argumentos se deben procesar en el orden en que se recibieron, pero no es necesario que se procesen todos en una sola llamada a la función Analizar(). Los comandos de ejecución prolongada no deben bloquear la ejecución de otros comandos.
  • Las funciones de la interfaz siempre se van a llamar desde un solo thread. El usuario debe poder llamar a la función de entrada de comando de forma segura desde el código dentro de su devolución(output) del callback.

Deben ser soportado los siguientes argumentos por el Procesador de Comandos:
  • Mostrar [argumentos] ... Muestra todos los argumentos de comando textualmente en la devolución(output) del callback, delimitados por espacios. Si no se especifican argumentos, muestra una línea vacía.
  • CuentaRegresiva <segundos> Hace una cuenta regresiva según los segundos ingresados, mostrando un mensaje cada segundo vía la devolución(output) del callback. Cuando el comando se procesa por primera vez, debe devolver "Faltan X cantidad de segundos". El mensaje debe repetirse una vez por segundo, cuando llegue a cero, debe mostrar "Cuenta regresiva terminada".

Si se ingresa un comando extraño/no sportado, que muestre "Comando no soportado" en la devolución(output) del callback.

Desde ya muchas gracias a todos, saludos.


Título: Re: C++ Challenge
Publicado por: RayR en 8 Mayo 2022, 22:04 pm
Una solución rápida que se me ocurre es esto:

La función que recibe los comandos del usuario los pondría en algún tipo de cola, de forma sincronizada (usando una región crítica, por ejemplo). Cuando el usuario llama a la función Analizar(), ésta va tomando cada comando de la cola (obviamente, de forma sincronizada) y ejecutándolo. Dado que no quieres que un comando bloquee la ejecución de otro, esta función podría lanzar un hilo que ejecute cada uno de ellos. Para que esto no sea muy ineficiente, te recomendaría usar un "pool", que podrías crear tú, o usar el de Windows (la familia de funciones *Threadpool* de la API de Windows).

El comando CuentaRegresiva lo podrías manejar dentro de un bucle y haciendo llamadas a Sleep(1000) luego de cada mensaje "Faltan X cantidad de segundos", porque como se ejecuta en su propio hilo, no bloquearía el programa; o algo más elegante sería usar funciones de colas de temporizadores (Timer Queues) que la API de Windows proporciona. Éstos se ejecutan de forma periódica; en tu caso harías que esto ocurriera una vez por segundo. Podrías pasarle a la función callback de cada timer un puntero a una variable con el valor inicial recibido en el comando CuentaRegresiva (10 si fueran 10 segundos, etc.) y ésta, en cada ejecución lo decrementaría. Una vez que ese valor llega a 0, detienes (destruyes) el timer.

Dado lo anterior, Inicializar() podría inicializar las regiones críticas, y Apagar() esperaría a que los hilos terminen su ejecución (mediante la función WaitFor* correspondiente al tipo de hilo que decidas usar).

No me detengo en cada punto de los que pusiste porque me parece que algunos son muy simples.  Creo que lo único que podría tener cierta complicación es el tema de procesar comandos sin que uno bloquee los demás, y quizás la implementación de la cuenta regresiva; de ahí que me centrara en estos temas.


Título: Re: C++ Challenge
Publicado por: Miseryk en 12 Mayo 2022, 12:27 pm
Una solución rápida que se me ocurre es esto:

La función que recibe los comandos del usuario los pondría en algún tipo de cola, de forma sincronizada (usando una región crítica, por ejemplo). Cuando el usuario llama a la función Analizar(), ésta va tomando cada comando de la cola (obviamente, de forma sincronizada) y ejecutándolo. Dado que no quieres que un comando bloquee la ejecución de otro, esta función podría lanzar un hilo que ejecute cada uno de ellos. Para que esto no sea muy ineficiente, te recomendaría usar un "pool", que podrías crear tú, o usar el de Windows (la familia de funciones *Threadpool* de la API de Windows).

El comando CuentaRegresiva lo podrías manejar dentro de un bucle y haciendo llamadas a Sleep(1000) luego de cada mensaje "Faltan X cantidad de segundos", porque como se ejecuta en su propio hilo, no bloquearía el programa; o algo más elegante sería usar funciones de colas de temporizadores (Timer Queues) que la API de Windows proporciona. Éstos se ejecutan de forma periódica; en tu caso harías que esto ocurriera una vez por segundo. Podrías pasarle a la función callback de cada timer un puntero a una variable con el valor inicial recibido en el comando CuentaRegresiva (10 si fueran 10 segundos, etc.) y ésta, en cada ejecución lo decrementaría. Una vez que ese valor llega a 0, detienes (destruyes) el timer.

Dado lo anterior, Inicializar() podría inicializar las regiones críticas, y Apagar() esperaría a que los hilos terminen su ejecución (mediante la función WaitFor* correspondiente al tipo de hilo que decidas usar).

No me detengo en cada punto de los que pusiste porque me parece que algunos son muy simples.  Creo que lo único que podría tener cierta complicación es el tema de procesar comandos sin que uno bloquee los demás, y quizás la implementación de la cuenta regresiva; de ahí que me centrara en estos temas.


Yo había pensado algo similar, me voy a poner a ver algunos conceptos que nombraste, muchas gracias por tu punto de vista, saludos (Y)