假设我有封装 asio::ip::tcp::socket 和deadline_timer 的类X。如果连接太慢,则使用计时器断开连接。这是X:
class X
{
public:
typedef boost::function<void(const error_code&)> Handler;
void f(Handler);
void close();
private:
void on_connected(const error_code&);
void on_timeout(const error_code&);
void on_work_is_done(const error_code&);
Handler h_;
socket s_;
deadline_timer t_;
};
函数 f 做了一些工作(发送,接收,...),然后像这样调用处理程序:
void on_work_is_done(const error_code& e)
{
//swapping handlers to release handler after function exits
Handler h;
h.swap(h_);
h(e);
}
在此期间,计时器 t 正在计时。所以我的问题是:什么是制作 X::close 的好方法?close() 必须关闭套接字 s 并停止计时器 t,而且它必须调用处理程序 h 似乎很自然,但只有在所有异步操作(在 s 和 t 上)都被取消之后。如果没有计时器,那么问题就解决了:
void X::close() { s.close(); }
异步操作将被取消,on_work_is_done() 将使用 err == operation_aborted 调用,这将被传递给处理程序,然后处理程序将被释放。一切都好。但是由于有 2 个对象,并且每个对象都可能有一些未决的异步操作,因此问题似乎更复杂。因为如果我们这样做
void X::close()
{
s.close();
t.cancel();
}
两个处理程序 (on_work_is_done, on_timeout) 都将被调用,但我们可以从最后调用的处理程序调用交换的 handler_(err)。有一些简单的解决方案吗?
我看到以下方法:
a) 添加 size_t counter_ ,它将在 X::close() 中设置为 2,每个处理程序将其减 1。因此使 counter_ == 0 的处理程序将调用 handler_(operation_aborted);
b) 运行 t.cancel() 并从 on_timeout(err) 如果 err == operation_aborted 调用 s.cancel 并从 on_work_is_done() 调用 handler_(operation_aborted)
还是整个方法不好,有更好的方法?