2012-05-10 9 views
7

Estoy usando boost::asio::io_service para administrar algunas comunicaciones TCP asíncronas. Eso significa que creo un boost::asio::ip::tcp::socket y le doy el io_service. Cuando comienzo a la comunicación que va esquemáticamente así:¿Cómo prioriza el trabajo boost :: asio :: io_service work?

Async Resolve -> Callback -> Async Connect -> Callback -> Async Write -> Callback -> Async Read

I omitido partes como la resolución y se unen. Simplemente asuma que el Socket ha sido vinculado a un puerto y el nombre del servidor está resuelto (así que conecte el significado estableciendo la conexión real al punto final)

Ahora el punto es que puedo iniciar varias conexiones Async con el mismo objeto io_service. Esto significa, por ejemplo, que mientras en mi hilo io_service el programa está a unos Async Write algunos datos, el hilo principal llamará a Async Resolve con el Socket (pero con el mismo io_service). Esto significa que mi io_service ahora tiene un trabajo paralelo que hacer, ¿qué me gustaría saber es cómo priorizará el trabajo?

Por ejemplo ir como esto

Main Thread    |  io_service Thread 
-------------------------+----------------------------------------------- 
SocketA->Async Connect | 
//Some other Stuff  |  SocketA->Callback from Async Connect 
         |  SocketA->Async Write 
SocketB->Async Connect |  
         |  --> ? 

Ahora en este punto tengo que admitir que no estoy muy seguro de cómo los io_service obras. En la cuarta línea, ahora hay dos funciones asincrónicas diferentes que deben ejecutarse.

¿Es io_service capaz de hacer el Async Connect y el Async Write simultáneamente? Si ese es el caso, está claro que siempre se llamará a la devolución de llamada desde la función que se haya completado primero.

Si el io_service es no capaz de hacerlo, ¿en qué orden hará el trabajo? Si se llama primero al SocketA Async Write, también se llamará primero a la devolución de llamada. En realidad, siempre habrá trabajo hasta que finalice toda la operación en SocketA.

EDIT:

Según comentan ereOns Trato de hacer mi pregunta un poco más preciso:

Desde el punto de vista de la rosca io_service - es el asíncrona SocketA Async Connect llamada o sincrónica? Desde la vista de mi hilo principal, por supuesto es asincrónico (simplemente despacha el comando y luego continúa). Pero en el hilo io_service ¿esta llamada específica Connect bloqueará otras operaciones?

En otras palabras: ¿Hay un solo io_service capaz de conectarse a un zócalo mientras está leyendo en otro?

Otro ejemplo sería si acabo de llamar 2 Async Connect en mi función principal justo después de unos a otros:

SocketA->AsyncConnect(); 
SocketB->AsyncConnect(); 

Digamos que el anfitrión de SocketA es un poco lento y se necesita que dos segundos para responder. Entonces, mientras SocketA intenta conectarse, ¿se conectaría SocketB mientras tanto o tendría que esperar hasta que SocketA termine/se agote el tiempo de espera?

+1

No estoy seguro de obtener su pregunta por completo, pero yo diría que Asio planteará los eventos lo antes posible, ya sea la conexión o la escritura, lo que ocurra primero, en un orden no especificado. Si puedo preguntar, ¿por qué crees que importa el orden? – ereOn

+0

@ereOn Agregué un poco de contenido a la pregunta para hacerlo un poco más preciso – Toby

Respuesta

3

Todo el trabajo se realiza en la secuencia donde se ejecuta io_service.run().

Sin embargo, la llamada a cualquier método async_voluntad no bloque de este hilo específico: se comporta exactamente como si io_service.run() llama select() en varios eventos, y "retornos" (llama a una devolución de llamada) cada vez que se produce un evento de este tipo. Es decir, si se llama:

socketA->async_connect(); 
socketB->async_connect(); 

socketB puede también conectarse antes socketA y la devolución de llamada asociado sería entonces llamado primero, aún en el hilo io_service.run() carreras.

Esa es toda la belleza de Boost Asio: se ocupa muy bien de las encuestas, de la espera y de la generación de eventos cuando es más apropiado, dejándote con la parte "fácil".

+1

Bien, esto es "realmente" asíncrono, lo que significa que los métodos 'async_' funcionan en paralelo. ¿Qué devolución de llamada se llamará primero depende de cuál de las 'funciones asincrónicas' 'regresa' primero? ¿Lo entendí bien? – Toby

+0

@Toby: Exactamente. – ereOn

+0

Debido a la nueva respuesta de "esto", tengo que volver a preguntar: estamos hablando desde el punto de vista del hilo IO_Service aquí. Estoy muy consciente de que async_call en el hilo principal regresará de inmediato. Sin embargo, se llamarán las devoluciones de llamada en el hilo io_service ... ¿no? – Toby

0

Aquí no debe tratar de predecir el orden de ejecución para las operaciones asíncronas. async_connect simplemente indica io_service y lo devuelve inmediatamente. El trabajo real se realiza en el bucle de procesamiento de eventos del objeto io_service (io_service::run), pero no se conocen los detalles exactos. Lo más probable es que utilice las funciones IO asíncronas específicas del sistema operativo.

No está claro lo que está tratando de lograr. Tal vez deberías usar operaciones sincrónicas. Tal vez deberías usar la funcionalidad de sincronización de subprocesos. Tal vez io_service::run_one le ayudará (se ejecuta como máximo un controlador).

Quizás desee llamar al io_service::run varias veces en subprocesos separados, creando un grupo de subprocesos. De esta forma, un manejador de finalización largo no bloqueará a todos los demás.

boost::asio::io_service service; 
const size_t ASIO_THREAD_COUNT = 3; 
boost::thread_group threadGroup; 
for (size_t i = 0; i < ASIO_THREAD_COUNT; ++i) 
     threadGroup.create_thread(boost::bind(&boost::asio::io_service::run, 
      &service, boost::system::error_code())); 
+0

Esto está mal. Si 'io_service :: run()' solo estaba haciendo llamadas de bloqueo en un hilo deportado, ¿cuál sería el sentido de Boost Asio? No es necesario crear varios subprocesos para eso, y mucho menos un grupo de subprocesos. Estás creando un horror para solucionar un problema que nunca existió. – ereOn

+0

Tal vez asumí demasiado al tratar de decir que uno no debería asumir demasiado. Pero se sabe que los manipuladores son llamados desde 'run'-thread. No estoy seguro de lo que no te gusta del grupo de subprocesos, sin embargo, todo está bien y ordenado con Boost.Asio: citando el [documento] (http://www.boost.org/doc/libs/1_49_0/doc/ html/boost_asio/overview/core/threads.html): 'Varios subprocesos pueden llamar a io_service :: run() para configurar un grupo de subprocesos desde el que se pueden invocar controladores de terminación'' –

+0

No hay nada de malo en un grupo de subprocesos cuando sea necesario. Pero para el caso específico aquí, es demasiado exagerado ya que Boost Asio está diseñado para manejar concienzudamente los eventos asincrónicos. – ereOn

Cuestiones relacionadas