0

Boost asioを使用して、いくつかのソケットを開きます。すべてのソケット情報を含むカスタムクラスへの共有ポインターを持つコレクションを使用します。このクラスには、受信ごとに異なることを行う必要があり、追加のパラメーターでバインドできないhandle_readため、の関数もあります。async_receive

私が抱えている問題は、ソケットを閉じるときにそのポインタへの最後の参照を削除するため、handle_readこのように有効な参照なしで関数が呼び出され、コードが壊れてしまうことです。

void SocketsAPI::do_close(const SocketInfo socket)
{
    log("do_close");
    if (!socket.m_socket || !socket.m_socket->is_open()) {
        return;
    }   
    boost::system::error_code errorcode;
    socket.m_socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, errorcode);
    if (errorcode) {
        trace("Closing failed: ", errorcode.message());
    }
    socket.m_socket->close(errorcode);
    if (errorcode) {
        trace("Closing2 failed: ", errorcode.message());
    }
    mapType::iterator iter = sockets.find(socket.key);
    if (iter != sockets.end()) {
        sockets.erase (iter);
    }
    log("do_close end");
}

確かに私はhandle_read関数が呼び出されることを望んでいませんが、それを避けることはできません。マルチスレッド実装(複数のスレッドを呼び出すio_service.run())でさらに悪いことにhandle_read、クローズがまだ処理されている間に呼び出されるので、「この」オブジェクトはハンドラーの任意のポイントで解放されます。

4

1 に答える 1

2

あなたは親密なようですが、Boost.Asio非同期メソッドを使用するアプリケーションで通常行われる共有所有権のセマンティクスを完全には理解していません。コールバックハンドラーをバインドshared_from_this()するときに使用して、非同期操作の期間中、コールバックハンドラーがスコープ内にとどまるようにします。ドキュメントはこれを非常にうまく説明しています。io_service::~io_service()

非同期操作を途中で停止する必要がある場合は、メソッドのソケットを閉じるのではなく、キャンセルSocketsAPI::do_close()してください。次に、コールバックにエラーコードが与えられ、そのエラーコードをboost::asio::error::operation_aborted使用して適切に対応できます。


handle_readcloseがまだ処理されている間に呼び出されるため、「this」オブジェクトはハンドラーの任意のポイントで解放されます。

これは実際には別の質問です。ハンドラコールバック内のデータ構造への排他的アクセスを確保するstrandには、 sを使用する必要があります。

于 2013-03-15T18:39:30.693 に答える