首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何欺骗boost::asio以允许仅移动处理程序

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

Stack Overflow用户
提问于 2013-06-20 18:26:31
回答 2查看 2.2K关注 0票数 18

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

代码语言:javascript
复制
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来解决(尽管不是很优雅)

代码语言:javascript
复制
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不允许仅移动处理程序背后的原因是什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-04-06 16:11:30

在Chris Kohlhoff回复我提交的bug之前,这里有一个简单的解决方法:

代码语言:javascript
复制
template <typename F>
struct move_wrapper : F
{
    move_wrapper(F&& f) : F(std::move(f)) {}

    move_wrapper(move_wrapper&&) = default;
    move_wrapper& operator=(move_wrapper&&) = default;

    move_wrapper(const move_wrapper&);
    move_wrapper& operator=(const move_wrapper&);
};

template <typename T>
auto move_handler(T&& t) -> move_wrapper<typename std::decay<T>::type>
{
    return std::move(t);
}

包装器声明了一个复制构造函数,诱使asio的机器提交,但从未定义它,因此复制将导致链接错误。

现在终于可以这样做了:

代码语言:javascript
复制
std::packaged_task<int()> pt([] {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    return 42;
});
std::future<int> fu = pt.get_future();

boost::asio::io_service io;
io.post(move_handler(pt));
std::thread(&boost::asio::io_service::run, &io).detach();

int result = fu.get();
assert(result == 42);
票数 13
EN

Stack Overflow用户

发布于 2015-01-30 22:49:11

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

代码语言:javascript
复制
shared_ptr<mutex> lock(mutex & m)
{
    m.lock();
    return shared_ptr<mutex>(&m, mem_fn(&mutex::unlock));
}

不需要编写自定义包装器。

提到Smart Pointer Programming Techniques,你甚至可以使用:

代码语言:javascript
复制
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现在可以用作:

代码语言:javascript
复制
shared_lock lock(m);

注意,由于shared_lock能够隐藏类型信息,因此mutex类型上没有模板化shared_ptr<void>

它可能会花费更多,但它也有一些好处(接收器可以接受shared_lock,你可以传递给它一个可升级的,共享的,唯一的锁,scope_guard,基本上任何BasicLockable或更好的锁

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17211263

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档