2017-08-16 15 views
1

私はfire-and-forget UDP送信関数の実装を非同期に同期させないように変更しようとしています。非同期送信バッファ(メモリソケットを増やす)のメモリを予約

現在の単純化された同期機能は次のようになります。

ssize_t UDPTransport::send_to(const char * buffer, size_t bufferSize) { 
    return mPSocket->send_to(boost::asio::buffer(buffer, bufferSize), mOutputEndpoint); 
} 

私はthread_groupを設定し、io_service::run()がそれを使用するように設定されているんです。ただし、この呼び出しが完了した後にbufferが存在するという保証はありません。私はバッファの内容を保存して、それがいつでも再利用できるように自由であることを知る必要があります。以下は簡単ですが、私がsend_toの呼び出しを2回発射した場合、handle_sendが同じ順序で呼び出されるという保証はなく、私はまだpop何かが必要であるかもしれません!

ssize_t UDPTransport::send_to(const char * buffer, size_t bufferSize) { 

    boost::asio::mutable_buffer b1 = boost::asio::buffer(buffer,bufferSize); 
    mMutex.lock(); 
    mQueue.push(b1); 

    mPSocket->async_send_to(mQueue.back(), mOutputEndpoint, 
          boost::bind(&UDPTransport::handle_send, this, 
             boost::asio::placeholders::error, 
             boost::asio::placeholders::bytes_transferred)); 

    mMutex.unlock(); 
    return bufferSize; 
} 

void UDPTransport::handle_send(const boost::system::error_code& error, 
           std::size_t bytes_transferred) 
{ 
    mMutex.lock(); 
    mQueue.pop(); 
    mMutex.unlock(); 
} 

非同期バッファを保存して不要になったときにクリーンアップするとよいでしょうか?

Reading onlineさらに簡単な方法でも下のように表示されますが、信頼できるかどうかはわかりません。ハンドラが呼び出された後でなければ、共有ポインタは自分自身の割り付けを解除しないのはなぜですか?

明らか
class Sender : public std::enable_shared_from_this<Sender> { 
public: 
    using CompletionHandler = 
     std::function<void(const boost::system::error_code& ec, 
         size_t bytes_transferred, 
         std::shared_ptr<Sender> sender)>; 

    ~Sender() = default; 

    template<typename... Args> 
    static std::shared_ptr<Sender> Create(Args&&... args) { 
    return std::shared_ptr<Sender>(new Sender(std::forward<Args>(args)...)); 
    } 

    void AsyncSendTo(const char* buffer, size_t buffer_size, 
        CompletionHandler completion_handler) { 
    data_.append(buffer, buffer_size); 
    socket.async_send_to(
     boost::asio::buffer(data_), endpoint_, 
     [self = shared_from_this(), 
     completion_handler = std::move(completion_handler)] 
     (const boost::system::error_code& ec, 
     size_t bytes_transferred) mutable { 
      completion_handler(ec, bytes_transferred, std::move(self)); 
     }); 
    } 

private: 
    Sender() = default; 
    Sender(const Sender&) = delete; 
    Sender(Sender&&) = delete; 
    Sender& operator=(const Sender&) = delete; 
    Sender& operator=(Sender&&) = delete; 

    SocketType socket_; 
    EndpointType endpoint_; 
    std::string data_; 
} 

、あなたはcompletion_handler年代を保証する必要があります。次の行に沿ってのstd :: enable_shared_from_this <>何かを継承するクラスでそれをラップすることです私は通常行うこと

ssize_t UDPTransport::send_to(const char * buffer, size_t bufferSize) 
{ 
    auto buf = std::make_shared<std::string>(buffer, bufferSize); 
    mPSocket->async_send_to(boost::asio::buffer(*buf), mOutputEndpoint, 
          boost::bind(&UDPTransport::handle_send, this, 
             boost::asio::placeholders::error, 
             boost::asio::placeholders::bytes_transferred)); 
    return bufferSize; 
} 
+1

あなたがおそらくリンクしているshared_ptrソリューションは、shared_ptrをラムダの値で取得するため、おそらく正しいです。ですから、ハンドラが呼び出されると、ハンドラ自体の割り当てを解除する必要があります。しかし、shared_ptrを使ったコードはそれをしません。 –

答えて

2

一生。しかし、それ以外の場合、完了ハンドラは有効なstd::shared_ptr<Sender>が返ってくるたびに送信され、送信者のデータがあれば必要な処理を行うことができます。

投稿した例では、bufはスコープを離れ、bindで初めてキャプチャしない限り、send_toの返品で破棄されます。

脚注1:は、コンパイラがlambdasに関してC++ 14互換であるかどうかによって削除する必要があります。

脚注2:動的な性質を絶対に利用する必要がない限り、bindから離れること。

関連する問題