2

假设我有封装 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)

还是整个方法不好,有更好的方法?

4

0 回答 0