4

boost :: asioを使用して、async_acceptを使用して接続を受け入れます。これはうまく機能しますが、1つの問題があり、それに対処する方法の提案が必要です。典型的なasync_acceptの使用:

  Listener::Listener(int port)
        : acceptor(io, ip::tcp::endpoint(ip::tcp::v4(), port))
        , socket(io) {
          start_accept();
  }

  void Listener::start_accept() {
      Request *r = new Request(io);
      acceptor.async_accept(r->socket(), 
        boost::bind(&Listener::handle_accept, this, r, placeholders::error));
  }

正常に動作しますが、問題があります。リクエストオブジェクトはプレーンな新規で作成されるため、メモリ「リーク」が発生する可能性があります。実際にはリークではなく、プログラムの停止時にのみリークしますが、valgrindを幸せにしたいです。

確かにオプションがあります:それをshared_ptrに置き換えて、すべてのイベントハンドラーに渡すことができます。これは、プログラムが停止するまで機能します。asioio_serviceが停止すると、すべてのオブジェクトが破棄され、リクエストが解放されます。しかし、この方法では、リクエストに対して常にアクティブなasioイベントが必要です。そうしないと、破棄されます。クラッシュする直接的な方法だと思うので、私もこのバリアントが好きではありません。

UPD 3番目のバリアント:Listenerアクティブな接続へのshared_ptrのリストを保持します。見栄えが良く、より良い方法が見つからない限り、これを使用することを好みます。欠点は、このスキーマではアイドル状態の接続で「ガベージコレクション」を実行できるため、安全ではありません。リスナーから接続ポインタを削除すると、すぐに破棄され、接続のハンドラの一部が他のスレッドでアクティブな場合にセグメンテーション違反が発生する可能性があります。mutexを使用すると、このcusを修正できません。この場合、ほぼすべてをロックする必要があります。

アクセプターを接続管理で機能させる方法はありますか?美しく安全な方法はありますか?何か提案を聞いてうれしいです。

4

3 に答える 3

2

このライブラリを使用するときにメモリリークを回避するための一般的なレシピは、を使用することshared_ptrです。io_service ドキュメントには、これが具体的に記載されています。

備考

上記の破棄シーケンスにより、プログラムはを使用してリソース管理を簡素化できshared_ptr<>ます。オブジェクトの有効期間が接続の有効期間(またはその他の非同期操作のシーケンス)にshared_pt関連付けられている場合、オブジェクトへのrは、それに関連付けられているすべての非同期操作のハンドラーにバインドされます。これは次のように機能します。

単一の接続が終了すると、関連するすべての非同期操作が完了します。対応するハンドラオブジェクトが破棄され、オブジェクトへのすべてのshared_ptr参照が破棄されます。プログラム全体をシャットダウンするために、io_service関数stop()が呼び出され、すべてのrun()呼び出しができるだけ早く終了します。上記で定義されたio_serviceデストラクタは、すべてのハンドラを破棄し、shared_ptrすべての接続オブジェクトへのすべての参照を破棄します。

シナリオでは、Listener::handle_accept()メソッドを変更してboost::shared_ptr<Request>パラメーターを取得します。あなたの2番目の懸念

リスナーから接続ポインタを削除すると、すぐに破棄されます。これにより、接続のハンドラの一部が他のスレッドでアクティブになっている場合に、セグメンテーション違反が発生する可能性があります。mutexを使用すると、このcusを修正できません。この場合、ほぼすべてをロックする必要があります。

クラスのテンプレートから継承することで軽減さboost::enable_shared_from_thisれます。

class Listener : public boost::enable_shared_from_this<Listener>
{
   ...
};

次に、ハンドラーをディスパッチするときは、のメンバー関数にバインドするときshared_from_this()の代わりにを使用します。thisListener

于 2012-10-02T00:00:00.077 に答える
0

興味のある人がいたら、私は別の方法を見つけました。Listenerアクティブな接続へのshared_ptrのリストを保持します。終了/終了する接続は、。でラップされio_service::postた呼び出しを介して行われます。通常、私は常にRequestのメソッドをstrandでラップします。これは、DDOSやスレッドセーフの点でより安全です。したがって、使用から呼び出すと、他のスレッドのsegfaultから保護されますListener::FinishConnectionasio::strandFinishConnectionpoststrand

于 2012-10-08T17:56:52.647 に答える
0

これがあなたの問題に直接関係しているかどうかはわかりませんが、Boost Asioライブラリ、特にacceptorあなたが言及したのと同じオブジェクトを使用することで、同様のメモリリークが発生していました。サービスを正しくシャットダウンしていなかったことが判明しました。一部の接続は開いたままになり、対応するオブジェクトはメモリから解放されません。以下を呼び出すと、 Valgrindによって報告されたリークが取り除かれました:

acceptor.close();

これが誰かに役立つことを願っています!

于 2016-06-10T17:16:27.483 に答える