2009-01-08 15 views
13

He estado jugando mucho con Boost.Asio en los últimos tiempos. Me gusta mucho la biblioteca ya que ofrece una manera fantástica de exprimir el rendimiento de los sistemas multinúcleo actuales.¿Cuál es la mejor manera de garantizar la vida útil válida de los objetos cuando se usa Boost.Asio?

Una pregunta que me he hecho varias veces, y he pensado que vale la pena mencionar la duración del objeto/la propiedad al hacer llamadas asíncronas con Asio.

El problema que he encontrado repetidamente es que a menudo tiene que "caducar" un objeto que todavía tiene devoluciones de llamada asincrónicas pendientes en su contra. Si ese objeto queda fuera del alcance antes de que se invoque la devolución de llamada, las cosas inevitablemente explotarán.

Para combatir esto, he comenzado a usar la plantilla boost::enable_shared_from_this como una clase base para la mayoría de las clases basadas en Asio. Esto funciona bien pero es un poco oneroso: generalmente esto también significa proteger el constructor y agregar un método de fábrica a la clase para garantizar que todas las instancias se creen dentro de un shared_ptr.

Solo quería saber cómo otras personas han abordado este problema. ¿Voy por esto de la mejor manera? ¿O tengo mi Asio.Foo todo mal?

Discute ... :)

Respuesta

1

Ese tipo de cosas no se limita a Asio. Hace poco escribí una clase de agrupamiento de subprocesos (usando Boost :: Thread) que tenía más o menos el mismo problema: los subprocesos llamaban a la clase de grupo de subprocesos que los creó para ver qué tarea tenían que hacer a continuación, utilizando un puntero simple y si la clase de grupo de subprocesos se destruyera con un subproceso hijo aún ejecutándose, el programa fallaría. Lo solucioné llamando al interrupt en cada uno de los subprocesos del destructor de grupo de subprocesos, luego esperando que todos ellos salgan antes de dejar que el destructor retorne.

Si entiendo su solución de puntero compartido, parece que está haciendo lo mismo en general, asegurando que el elemento no pueda destruirse hasta que ya no sea necesario. Una solución estéticamente agradable también. No veo una mejor respuesta para este tipo de problema.

+0

Es interesante mencionar ese escenario: mi colega (conocido aquí como Alan) estaba haciendo lo mismo que usted y mencioné la "solución" que había encontrado porque para mí era el mismo problema. Sin embargo, todavía no estoy contento con esto: no me gusta la falta de determinismo, pero eso está bien – jkp

2

El uso de boost::enable_shared_from_this es más o menos la forma de hacerlo. Además, consulte el uso de boost::weak_ptr si necesita referencias al objeto que no debe conservar el objeto si son las únicas referencias que permanecen.

Un buen ejemplo del uso de weak_ptr: uso enable_shared_from_this en mi clase de socket que utiliza boost::asio. El marco boost::asio es lo único que almacena referencias persistentes al objeto, a través de controladores de lectura y escritura. Por lo tanto, cuando se llama al destructor del socket, sé que el socket está cerrado y puedo "hacer cosas" en un controlador para limpiar ese socket cerrado. La aplicación que usa el socket solo tiene una referencia weak_ptr, que promueve a shared_ptr cuando quiere trabajar con el socket (generalmente para escribir en él). Esa promoción se puede verificar en caso de que falle el socket, aunque el manejador cercano del socket normalmente limpia todas las referencias weak_ptr de forma adecuada antes de que eso ocurra.

Cuestiones relacionadas