2012-02-07 14 views
4

私は、TCPを介してメッセージをディスパッチできるクラスを持っています。ここでは単純化されたインタフェース:shared_ptrを使ったAsio-handlingリゾルバとソケットのブーケ

class CommandScreenshot : public CameraCommand 
{ 
public: 
    CommandScreenshot(); 
    ~CommandScreenshot(); 
    void Dispatch(boost::shared_ptr<boost::asio::io_service> io_service); 

private: 
    void resolve_handler(const boost::system::error_code& err, 
      boost::asio::ip::tcp::resolver::iterator endpoint_iterator); 

}; 

にあなたが、私は実際には非同期操作を開始することを目的としている機能Dispatchを持って見ることができるように:他に

void CommandScreenshot::Dispatch(boost::shared_ptr<boost::asio::io_service> io_service) 
{ 
    boost::asio::ip::tcp::resolver resolver(*io_service); 
    boost::asio::ip::tcp::resolver::query query(m_hostname,"http"); 
    resolver.async_resolve(query,boost::bind(&CommandScreenshot::resolve_handler,this,boost::asio::placeholders::error, boost::asio::placeholders::iterator)); 
    return; 
} 

すべては、次のコールバックで行われます機能。 io_serviceオブジェクトと対応するスレッドは別のクラス(CommandScreenshotのインスタンスを持ち、Dispatch関数を呼び出します)によって管理されます。

ブーストとの簡単なTCP接続を実装するには、resolverオブジェクトとsocketオブジェクトが必要です(どちらもio_serviceオブジェクトにバインドされています)。 io_serviceオブジェクトはその時点でのみ渡されるので、関数が呼び出され、クラスコンストラクタでそれらを初期化できません。 また、それらをクラスメンバーとして宣言し、関数自体で初期化することはできません。

私の最初のアイデアは、関数呼び出し時にそれらを初期化し、それらを私の完了ハンドラに渡すことでした。つまり、関数が呼び出されるたびに両方のオブジェクトを宣言し、io_serviceにバインドすることを意味します。その後、async_resolveで、私はboost::bindを介してパラメータとして両方を追加します。それは私のresolve_handlerは複数の引数を期待することを意味する - 例えば:

void resolve_handler(const boost::system::error_code& err, 
      boost::asio::ip::tcp::resolver::iterator endpoint_iterator, 
      boost::asio::ip::tcp::resolver resolver, 
      boost::asio::ip::tcp::socket socket); 

私は実際にこれがまともなかつ公正な解決策であることを疑います。通常、これらのオブジェクトはメンバーとして保持され、コピーされないようにする必要があります - 私は別の考えを与え、私の心はboost::shared_ptrに私を連れて行きました。私のヘッダーで

それはこのようになりましたになります。

// Stuff above stays the same 
private: 
    boost::shared_ptr<boost::asio::ip::tcp::resolver> m_resolver; 
    boost::shared_ptr<boost::asio::ip::tcp::socket> m_socket; 
// Stuff below stays the same 

そして、実装は次のようになります。これにより

void CommandScreenshot::Dispatch(boost::shared_ptr<boost::asio::io_service> io_service) 
{ 
    m_resolver.reset(new boost::asio::ip::tcp::resolver(*io_service)); 
    m_socket.reset(new boost::asio::ip::tcp::socket(*io_service)); 
    boost::asio::ip::tcp::resolver::query query(m_hostname,"http"); 
    m_resolver->async_resolve(query,boost::bind(&CommandScreenshot::resolve_handler,this,boost::asio::placeholders::error, boost::asio::placeholders::iterator)); 
    return; 
} 

を、私も4(または多分のように周りにコピーする必要はありませんより多くの)パラメータを定義し、それらを結合します。ソケットオブジェクトが必要なときには、クラスメンバーであるポインタを介してアクセスできます。

今私の簡単な質問は - >これは正しい方法ですか?非同期部分が終了していなくても、関数は複数回呼び出すことができます。 (私はソケットとリゾルバをミューテックスで保護しなければならないことを知っています)。しかし、これはきれいです、毎回私はDispatch関数を呼び出すときに新しいオブジェクトを作成するのですか? resetコールは不必要なメモリを取り除くのに十分ですか?

私はこれが特定の短い質問のための長いテキストであり、さらにはtiselfでもエラーがないことを知っています。しかし、私はいつもそれが私が行っているまともな方法であるかどうか、そしてより良いものがあれば、どうやってそれをするのかを知りたい。

答えて

3

memebersをasioオブジェクトにshared_ptrとして定義するという考えは大丈夫です。あなたは(」あなたを想定したASIOのオブジェクトに対するすべての操作がio_serviceを実行するスレッドで行わていることを確認した場合、あなたは、明示的なロックを回避することができ、他に

if (!m_resolver) 
{ 
    m_resolver.reset(...); 
} 

:しかし、あなたは&は彼らに再びたびに作成、破棄べきではありませんio_serviceごとに1つのスレッドがあります)。これを行うには、インタフェース関数の実装を分離し、post()を使用します。もちろん、オブジェクトのライフタイムコントロールを簡素化するためにshared_from_thisというイディオムを使用してください:

void CommandScreenshot::someMethod(Arg1 arg1, Arg2 arg2)    
{ 
    io_.post(bind(&CommandScreenshot::someMethodImpl, shared_from_this, arg1, arg2)); 
} 
//... 
void CommandScreenshot::someMethodImpl(Arg1 arg1, Arg2 arg2)    
{ 
    // do anything you want with m_resolver, m_socket etc. 
} 
関連する問題