我有一个围绕 boost::asio::io_service
运行的对象,它具有一些属性。类似的东西:
class Foo
{
private:
// Not an int in my real code, but it doesn't really matter.
int m_bar;
boost::asio::io_service& m_io_service;
boost::asio::strand m_bar_strand;
};
m_bar
只能从通过链 m_bar_strand
调用的处理程序中使用。这使我不会从这些处理程序中锁定。
为了从运行 io_service::run()
的线程外部设置 m_bar
属性,我编写了一个 asynchronous_setter,如下所示:
class Foo
{
public:
void async_get_bar(function<void (int)> handler)
{
m_bar_strand.post(bind(&Foo::do_get_bar, this, handler));
}
void async_set_bar(int value, function<void ()> handler)
{
m_bar_strand.post(bind(&Foo::do_set_bar, this, value, handler));
}
private:
void do_get_bar(function<void (int)> handler)
{
// This is only called from within the m_bar_strand, so we are safe.
// Run the handler to notify the caller.
handler(m_bar);
}
void do_set_bar(int value, function<void ()> handler)
{
// This is only called from within the m_bar_strand, so we are safe.
m_bar = value;
// Run the handler to notify the caller.
handler();
}
int m_bar;
boost::asio::io_service& m_io_service;
boost::asio::strand m_bar_strand;
};
这非常有效,但现在我想编写一个 set_bar
的同步版本,它设置值并仅在设置有效时返回。它仍然必须保证有效集将出现在 m_bar_strand
中。理想情况下,可以重入。
我可以想象带有信号量的解决方案可以从处理程序中进行修改,但我提出的所有内容似乎都很老套而且真的不优雅。 Boost/Boost Asio 中有什么允许这样的事情吗?
您将如何着手实现此方法?
最佳答案
如果你需要同步等待一个值被设置,那么Boost.Thread的futures
可能会提供一个优雅的解决方案:
The futures library provides a means of handling synchronous future values, whether those values are generated by another thread, or on a single thread in response to external stimuli, or on-demand.
简而言之,一个boost::promise
创建并允许在其上设置值。稍后可以通过关联的 boost::future
检索该值.这是一个基本示例:
boost::promise<int> promise;
boost::unique_future<int> future = promise.get_future();
// start asynchronous operation that will invoke future.set_value(42)
...
assert(future.get() == 42); // blocks until future has been set.
这种方法还有两个显着的好处:
future
是 C++11 的一部分。- 异常甚至可以通过
promise::set_exception()
传递给future
,支持以优雅的方式向调用者提供异常或错误。
这是一个基于原始代码的完整示例:
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
class Foo
{
public:
Foo(boost::asio::io_service& io_service)
: m_io_service(io_service),
m_bar_strand(io_service)
{}
public:
void async_get_bar(boost::function<void(int)> handler)
{
m_bar_strand.post(bind(&Foo::do_get_bar, this, handler));
}
void async_set_bar(int value, boost::function<void()> handler)
{
m_bar_strand.post(bind(&Foo::do_set_bar, this, value, handler));
}
int bar()
{
typedef boost::promise<int> promise_type;
promise_type promise;
// Pass the handler to async operation that will set the promise.
void (promise_type::*setter)(const int&) = &promise_type::set_value;
async_get_bar(boost::bind(setter, &promise, _1));
// Synchronously wait for promise to be fulfilled.
return promise.get_future().get();
}
void bar(int value)
{
typedef boost::promise<void> promise_type;
promise_type promise;
// Pass the handler to async operation that will set the promise.
async_set_bar(value, boost::bind(&promise_type::set_value, &promise));
// Synchronously wait for the future to finish.
promise.get_future().wait();
}
private:
void do_get_bar(boost::function<void(int)> handler)
{
// This is only called from within the m_bar_strand, so we are safe.
// Run the handler to notify the caller.
handler(m_bar);
}
void do_set_bar(int value, boost::function<void()> handler)
{
// This is only called from within the m_bar_strand, so we are safe.
m_bar = value;
// Run the handler to notify the caller.
handler();
}
int m_bar;
boost::asio::io_service& m_io_service;
boost::asio::strand m_bar_strand;
};
int main()
{
boost::asio::io_service io_service;
boost::asio::io_service::work work(io_service);
boost::thread t(
boost::bind(&boost::asio::io_service::run, boost::ref(io_service)));
Foo foo(io_service);
foo.bar(21);
std::cout << "foo.bar is " << foo.bar() << std::endl;
foo.bar(2 * foo.bar());
std::cout << "foo.bar is " << foo.bar() << std::endl;
io_service.stop();
t.join();
}
它提供以下输出:
foo.bar is 21
foo.bar is 42
关于c++ - 如何等待 asio 处理程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20709725/