如何欺骗boost :: asio以允许只移动处理程序

时间:2013-06-20 10:26:31

标签: c++ boost c++11 boost-asio move-semantics

在RPC通信协议中,在调用方法之后,我将“完成”消息发送回调用者。由于方法是以并发方式调用的,因此包含响应的缓冲区(std::string)需要由互斥锁保护。我想要实现的目标如下:

void connection::send_response()
{
    // block until previous response is sent
    std::unique_lock<std::mutex> locker(response_mutex_);

    // prepare response
    response_ = "foo";

    // send response back to caller. move the unique_lock into the binder
    // to keep the mutex locked until asio is done sending.
    asio::async_write(stream_,
                      asio::const_buffers_1(response_.data(), response_.size()),
                      std::bind(&connection::response_sent, shared_from_this(),
                                _1, _2, std::move(locker))
                      );
}

void connection::response_sent(const boost::system::error_code& err, std::size_t len)
{
    if (err) handle_error(err);
    // the mutex is unlocked when the binder is destroyed
}

但是,由于boost::asio需要handlers to be CopyConstructible

,因此无法编译

使用以下共享锁定类而不是unique_lock可以解决问题(尽管不是很优雅):

template <typename Mutex>
class shared_lock
{
public:
    shared_lock(Mutex& m)
    : p_(&m, std::mem_fn(&Mutex::unlock))
    { m.lock(); }

private:
    std::shared_ptr<Mutex> p_;
};

boost::asio不允许仅限移动处理程序的原因是什么?

1 个答案:

答案 0 :(得分:2)

这是一个更简单的解决方法:

shared_ptr<mutex> lock(mutex & m)
{
    m.lock();
    return shared_ptr<mutex>(&m, mem_fn(&mutex::unlock));
}

无需编写自定义包装器。

参考Smart Pointer Programming Techniques,您甚至可以使用:

class shared_lock    {
private:    
    shared_ptr<void> pv;    
public:    
    template<class Mutex> explicit shared_lock(Mutex & m): pv((m.lock(), &m), mem_fn(&Mutex::unlock)) {}
};

shared_lock现在可以用作:

shared_lock lock(m);

请注意,由于shared_lock能够隐藏类型信息,因此mutex类型不会模仿shared_ptr<void>

它可能会花费更多,但它也有一些事情要做(接收方可以使用shared_lock并且你可以传递一个可升级的,共享的,唯一的锁,scope_guard,基本上任何BasicLockable或“更好”