假设我有类X封装了asio :: ip :: tcp :: socket和deadline_timer。如果连接速度太慢,则用于断开连接。这是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()必须关闭套接字并停止计时器t,它必须调用处理程序h似乎非常自然,但只有在所有异步操作(在s和t上)被取消之后。如果没有计时器,那么问题就解决了:
void X::close() { s.close(); }
将取消异步操作并使用err == operation_aborted调用on_work_is_done(),这将传递给处理程序,然后处理程序将被释放。一切都好。但由于有2个对象,并且每个对象可能都有一些待处理的异步操作,因此问题似乎更复杂。因为如果我们这样做
void X::close()
{
s.close();
t.cancel();
}
将调用两个处理程序(on_work_is_done,on_timeout),但我们可以从最后调用的处理程序中调用swapped 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)
或者整个方法都很糟糕,还有更好的方法吗?