2011-09-03 20 views
5

Así que he creado una clase de socket que usa la biblioteca boost :: asio para realizar lecturas y escrituras asíncronas. Funciona, pero tengo algunas preguntas.boost :: Asio operaciones y recursos asíncronos

Aquí está un ejemplo de código básica:

class Socket 
{ 
public: 
    void doRead() 
    { 
     m_sock->async_receive_from(boost::asio::buffer(m_recvBuffer), m_from, boost::bind(&Socket::handleRecv, this, boost::asio::placeholders::error(), boost::asio::placeholders::bytes_transferred())); 
    } 

    void handleRecv(boost::system::error_code e, int bytes) 
    { 
     if (e.value() || !bytes) 
     { 
      handle_error(); 
      return; 
     } 
     //do something with data read 
     do_something(m_recvBuffer); 

     doRead(); //read another packet 
    } 

protected: 
    boost::array<char, 1024> m_recvBuffer; 
    boost::asio::ip::udp::endpoint m_from; 
}; 

Parece que el programa leerá un paquete, manejarlo, a continuación, se preparan para leer otro. Sencillo. Pero, ¿y si configuro un grupo de subprocesos? ¿Debería la siguiente llamada a doRead() ser antes o después de manejar los datos leídos? Parece que si se pone antes de do_something(), el programa puede comenzar inmediatamente a leer otro paquete, y si se coloca después, el hilo está vinculado haciendo lo que do_something() hace, lo que posiblemente podría tomar un tiempo. Si pongo el doRead() antes del manejo, ¿significa eso que los datos en m_readBuffer podrían cambiar mientras lo estoy manejando?

Además, si estoy usando async_send_to(), ¿debo copiar los datos que se enviarán a un búfer temporal, porque el envío real podría no ocurrir hasta que los datos hayan caído fuera del alcance? es decir

void send() 
{ 
    char data[] = {1, 2, 3, 4, 5}; 
    m_sock->async_send_to(boost::buffer(&data[0], 5), someEndpoint, someHandler); 
} //"data" gets deallocated, but the write might not have happened yet! 

Además, cuando la toma está cerrado, el handleRecv será llamada con lo que indica que se interrumpió un error. Si hago

Socket* mySocket = new Socket()... 
... 
mySocket->close(); 
delete mySocket; 

podría causar un error, porque hay una posibilidad de que mySocket se eliminarán antes de handleRecv() obtiene la llamada/terminado?

+0

+1 para una buena pregunta, pero en el futuro sugiero dividirla en preguntas separadas en Stackoverflow. –

Respuesta

2

Muchas preguntas aquí, intentaré abordarlas de a una por vez.

¿Pero y si configuro un grupo de subprocesos?

La forma tradicional de utilizar un grupo de subprocesos con Boost.Asio es invocar io_service::run()from multiple threads. Sin embargo, tenga en cuenta que esta no es una respuesta única para todos, puede haber problemas de escalabilidad o rendimiento, pero esta metodología es, con mucho, la más fácil de implementar. Hay muchos questions similares en Stackoverflow con más información.

¿Debería la próxima llamada a doRead ser antes o después de manejar los datos de de lectura? Parece que si se pone antes de do_something(), el programa puede comenzar inmediatamente a leer otro paquete, y si se pone después, , el hilo está atado haciendo lo que haga, lo que podría llevar .

Esto realmente depende de lo que do_something() necesita hacer con m_recvBuffer. Si desea invocar do_something() en paralelo con doRead() usando io_service::post(), es probable que necesite hacer una copia de m_recvBuffer.

Si pongo la doRead() antes de la manipulación, qué que significa que los datos en m_readBuffer podría cambiar mientras yo estoy manejando?

como mencioné anteriormente, sí, esto puede suceder y sucederá.

Además, si estoy usando async_send_to(), debería copiar los datos a enviar en un búfer temporal, debido a que el envío real podría no ocurrir hasta después de los datos han caído fuera de alcance?

A medida que el documentation describes, corresponde a la persona que llama (usted) para asegurar la memoria intermedia permanece en su alcance por la duración de la operación asincrónica. Como sospechaba, su ejemplo actual invoca un comportamiento no definido porque data[] saldrá del alcance.

Además, cuando la toma está cerrado, el handleRecv() serán llamados con lo que indica que se interrumpió un error.

Si desea seguir utilizando el zócalo, utilizar cancel() a interrupt outstanding operaciones asincrónicas. De lo contrario, close() funcionará. El error pasado a las operaciones asincrónicas sobresalientes en cualquier escenario es boost::asio::error::operation_aborted.

Cuestiones relacionadas