2010-05-28 13 views
15

Estoy buscando una forma de hacer un registro asíncrono y seguro para subprocesos en mi proyecto C++, si es posible en un archivo. Actualmente estoy usando cerr y clog para la tarea, pero dado que son sincrónicos, la ejecución se detiene brevemente cada vez que se registra algo. Es una aplicación relativamente pesada en gráficos, por lo que este tipo de cosas es bastante molesto.Registro asíncrono seguro de subprocesos en C++

El nuevo registrador debe usar E/S asíncronas para deshacerse de estas pausas. La seguridad de subprocesos también sería deseable ya que pretendo agregar algo de subprocesamiento básico pronto.

Consideré un enfoque de un archivo por hilo, pero parecía que eso haría que manejar los registros fuera una pesadilla. ¿Alguna sugerencia?

Respuesta

4

Esto es MUY posible y práctico. ¿Cómo puedo saber? Escribí exactamente eso en mi último trabajo. Desafortunadamente (para nosotros), ahora poseen el código. :-) Tristemente, ni siquiera lo usan.

Tengo la intención de escribir una versión de código abierto en el futuro cercano. Mientras tanto, puedo darte algunas pistas.

  1. Los manipuladores de E/S son solo nombres de funciones. Puede implementarlos para su propia clase de registro para que su registrador sea compatible con cout/cin.
  2. Las funciones de su manipulador pueden tokenizar las operaciones y almacenarlas en una cola.
  3. Se puede bloquear un hilo en esa cola esperando a que salgan trozos de registro. Luego procesa las operaciones de cadena y genera el registro real.

Esto es intrínsecamente compatible con hilos ya que está utilizando una cola. Sin embargo, aún desea colocar una protección tipo mutex alrededor de la escritura en la cola para que un registro determinado < < "cosas" < < "más cosas"; la operación de tipo permanece line-atomic.

¡Diviértete!

+0

¿No significaría un mutex que si un hilo ya está intentando escribir, tendría que girar hasta que se desbloqueara? ¿Cómo ayuda esto? – Electro

+0

No demoraría la conversión del objeto en la secuencia. Ponerlo en otro hilo significa tener que sincronizarlo ... y es probable que duela como el infierno. –

+0

@Electro - no gira, pero bloquea. Pero si no está procesando cadenas, es un intervalo MUY corto para cargar la cola. El procesamiento de cadena se realiza mediante el hilo de registro. @Matthieu, hacer el procesamiento de cadenas en tiempo real duele mucho más que cualquier bloqueo de mutex mientras se carga una cola. –

0

Creo que el enfoque adecuado no es un archivo por hilo, sino un hilo por archivo. Si un solo archivo (o recurso en general) en su sistema solo es accedido por un hilo, la programación segura de subprocesos se vuelve mucho más fácil.

Entonces, ¿por qué no hacer de Logger un hilo dedicado (o varios hilos, uno por archivo, si está registrando cosas diferentes en archivos diferentes) y en todos los otros hilos, escribir en el registro colocaría el mensaje en la cola de entrada en el hilo Logger apropiado, que llegaría a él una vez que haya terminado de escribir el mensaje anterior. Todo lo que se necesita es un mutex para proteger la cola de la adición de un evento mientras Logger lee un evento, y una condición para que Logger espere cuando su cola esté vacía.

+0

Puede escapar sin utilizar un mutex con una cola libre de bloqueos. La variable condicional es mucho más diferente sin embargo. Dependiendo de la carga, es posible que prefiera girar en lugar de ir a dormir y despertar más tarde. También depende de si tienes o no núcleos inactivos :) –

+0

Si hay algo ocupado esperando en nuestro sistema, watchdog matará a toda la aplicación :) – Cubbi

1

¿Ha considerado utilizar una biblioteca de registro.

Hay varios disponibles, descubrí Pantheios recientemente y realmente parece ser bastante increíble.

Es más un registrador front-end, puede personalizar qué sistema se utiliza. Puede interactuar con ACE o log4cxx por ejemplo y parece muy fácil de usar y configurar. La principal ventaja es que utiliza operadores de tipo seguro, lo que siempre es genial.

Si lo que desea es una biblioteca de registro barebone:

  • ACE
  • log4c *
  • Boost.Log

elegir cualquier :)

deben tener en cuenta que se trata de Es posible implementar colas sin bloqueo en C++ y que son geniales para el registro.

+0

Hm, no creo que quiera traer ninguno de esos.Los dos primeros parecen exagerados, y este último tuvo muchos problemas de rendimiento en su revisión, que fue una de las razones por las que no lo agregaron a la colección propia de Boost. – Electro

17

Me di cuenta de esto 1 año + hilo viejo. Tal vez el registrador asincrónico que escribí podría ser de interés.

http://www.codeproject.com/KB/library/g2log.aspx

G2log utiliza una cola de mensajes protegidos para reenviar las entradas del registro a un trabajador de fondo que el disco lenta accesos.

Lo he intentado con una cola libre de bloqueos que aumenta el tiempo promedio para una llamada de LOG pero disminuye el peor de los casos, sin embargo ahora estoy usando la cola protegida ya que es multiplataforma. Se ha probado en Windows/Visual Studio 2010 y Ubuntu 11.10/gcc4.6.

Se ha publicado como de dominio público, por lo que puede hacer lo que quiera sin ningún compromiso.

+0

Lo habitual que hago si el registro no debe conducir a ningún bloqueo (por ejemplo, depuración de condiciones de carrera con impresiones ... ¡ojalá funcione y es simple!) Es utilizar un hilo de cola de mensajes locales que almacena tokens con marcas de tiempo (bueno, en este caso probablemente sea mejor hacerlo directamente con async IO). Si necesita los datos, solo tiene que ordenar la salida más adelante y es bastante engorroso para el registro general, pero tiene la cantidad de sincronización más baja posible: nada. – Voo

+0

Lo que es importante, por supuesto, no solo es ser seguro para subprocesos, y un bloqueo mínimo, sino también asegurarse de que las entradas de registro estén archivadas si el programa falla (falla de segmentación, error de coma flotante, etc.). G2log proporciona que al usar un manejador de señal, en caso de una "señal fatal", vacía las entradas en cola al archivo antes de que la señal continúe (y cancela el programa) –

+0

@ KjellHedström - siga los pasos en este enlace http: // stackoverflow. com/help/user-merge para fusionar sus cuentas. – ChrisF

0

Tuve el mismo problema y creo que he encontrado la solución perfecta. Te presento una biblioteca de un solo encabezado llamada loguru: https://github.com/emilk/loguru

Es simple de usar, portátil, configurable, basado en macro y por defecto no contiene #include nada (por ese dulce y dulce tiempo de compilación).

Cuestiones relacionadas