Igorがコメントで述べているように、完了ハンドラーはすでにキューに入れられています。
このシナリオは、操作が実行されてからハンドラーが呼び出されるまでの時間の分離の結果です。、、、およびのドキュメントはio_service::run()
、操作ではなく、ハンドラーに言及するためのものです。シナリオでは、操作と操作は同じイベントループの反復で完了します。これにより、両方のハンドラーが不特定の順序で遅延呼び出し用に追加されます。io_service::run_one()
io_service::poll()
io_service::poll_one()
socket::async_connect()
deadline_timer::async_wait()
io_service
シナリオを強調する次のスニペットについて考えてみます。
void handle_wait(const boost::system::error_code& error)
{
if (error) return;
socket_.close();
}
timer_.expires_from_now(boost::posix_time::seconds(30));
timer_.async_wait(&handle_wait);
socket_.async_connect(endpoint_, handle_connect);
boost::this_thread::sleep(boost::posix_time::seconds(60));
io_service_.run_one();
がio_service_.run_one()
呼び出されると、との両方socket::async_connect()
のdeadline_timer::async_wait()
操作が完了し、不特定の順序で内部からの呼び出しの準備ができている可能性がhandle_wait
あります。この不特定の順序を適切に処理するには、操作のステータス()だけに依存するのではなく、内部から追加のロジックを実行して現在の状態を照会し、他のハンドラーが呼び出されたかどうかを判断する必要があります。handle_connect
io_service
handle_wait()
handle_connect()
error_code
他のハンドラーが呼び出したかどうかを判断する最も簡単な方法は次のとおりです。
- で、
handle_connect()
でソケットがまだ開いているかどうかを確認しますis_open()
。ソケットがまだ開いている場合は、handle_timer()
呼び出されていません。handle_timer()
実行されたことを示すクリーンな方法handle_connect()
は、有効期限を更新することです。
- で
handle_timer()
、有効期限が経過しているかどうかを確認します。これが当てはまる場合は、handle_connect()
実行されていないので、ソケットを閉じます。
結果のハンドラーは次のようになります。
void handle_wait(const boost::system::error_code& error)
{
// On error, return early.
if (error) return;
// If the timer expires in the future, then connect handler must have
// first.
if (timer_.expires_at() > deadline_timer::traits_type::now()) return;
// Timeout has occurred, so close the socket.
socket_.close();
}
void handle_connect(const boost::system::error_code& error)
{
// The async_connect() function automatically opens the socket at the start
// of the asynchronous operation. If the socket is closed at this time then
// the timeout handler must have run first.
if (!socket_.is_open()) return;
// On error, return early.
if (error) return;
// Otherwise, a connection has been established. Update the timer state
// so that the timeout handler does not close the socket.
timer_.expires_at(boost::posix_time::pos_infin);
}
Boost.Asioは、タイムアウトを処理するためのいくつかの例を提供します。