boost :: asio асинхронные операции и ресурсы - PullRequest
5 голосов
/ 03 сентября 2011

Итак, я создал класс сокетов, который использует библиотеку boost :: asio для асинхронного чтения и записи. Это работает, но у меня есть несколько вопросов.

Вот базовый пример кода:

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;
};

Кажется, что программа прочитает пакет, обработает его, а затем подготовится к прочтению другого. Просто. Но что если я настрою пул потоков? Должен ли следующий вызов doRead() быть до или после обработки прочитанных данных? Похоже, что если он установлен до do_something(), программа может немедленно начать чтение другого пакета, а если он будет помещен после, поток связывается с тем, что делает do_something(), что может занять некоторое время. Если я поставлю doRead() перед обработкой, означает ли это, что данные в m_readBuffer могут измениться во время обработки?

Кроме того, если я использую async_send_to(), должен ли я скопировать данные для отправки во временный буфер, поскольку фактическая отправка может произойти только после того, как данные выйдут из области видимости? т.е.

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!

Кроме того, когда сокет закрыт, handleRecv будет вызван с ошибкой, указывающей, что он был прерван. Если я сделаю

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

может ли это вызвать ошибку, потому что есть вероятность, что mySocket будет удалено до того, как handleRecv() будет вызван / завершен?

1 Ответ

2 голосов
/ 05 сентября 2011

Здесь много вопросов, я постараюсь ответить на них по одному.

Но что, если я настрою пул потоков?

Традиционный способ использования пула потоков с Boost.Asio заключается в вызове io_service::run() из нескольких потоков . Остерегайтесь, это не универсальный ответ, хотя могут быть проблемы с масштабируемостью или производительностью, но эта методология является самой простой в реализации. В Stackoverflow есть много похожих вопросов с дополнительной информацией.

Должен ли следующий вызов doRead быть до или после обработки чтения данные? Похоже, что если он ставится перед do_something (), программа может сразу начать читать другой пакет, и если он будет поставлен после, поток связан с тем, что делает do_something, что может возможно, потребуется время.

Это действительно зависит от того, что do_something() нужно сделать с m_recvBuffer. Если вы хотите вызвать do_something() параллельно с doRead(), используя io_service::post(), вам, вероятно, потребуется сделать копию m_recvBuffer.

Если я поставлю doRead () перед обработкой, это означает, что данные в m_readBuffer могут измениться, пока я обрабатываю их?

Как я уже упоминал ранее, да, это может и произойдет.

Кроме того, если я использую async_send_to(), я должен скопировать данные для отправки во временный буфер, потому что фактическая отправка может не произойти до тех пор, пока данные не выйдут за рамки?

Как указано в документации , вызывающий объект (вы) должен убедиться, что буфер остается в области действия на время асинхронной операции. Как вы и подозревали, ваш текущий пример вызывает неопределенное поведение, потому что data[] выйдет из области видимости.

Кроме того, когда сокет закрыт, будет вызываться handleRecv() с ошибкой, указывающей, что она была прервана.

Если вы хотите продолжать использовать сокет, используйте от cancel() до прерываний, ожидающих асинхронных операций. В противном случае close() будет работать. Ошибка, переданная в незавершенные асинхронные операции в любом сценарии, является boost::asio::error::operation_aborted.

...