Timeout#~Timeout(), #Cancel(): support boost::asio::io_context running on multiple threads

This commit is contained in:
Alexander A. Klimov 2024-11-29 14:16:08 +01:00
parent cb51649363
commit 959b162913
3 changed files with 33 additions and 5 deletions

View File

@ -148,6 +148,8 @@ void AsioConditionVariable::Wait(boost::asio::yield_context yc)
void Timeout::Cancel() void Timeout::Cancel()
{ {
m_Cancelled->store(true);
boost::system::error_code ec; boost::system::error_code ec;
m_Timer.cancel(ec); m_Timer.cancel(ec);
} }

View File

@ -3,10 +3,12 @@
#ifndef IO_ENGINE_H #ifndef IO_ENGINE_H
#define IO_ENGINE_H #define IO_ENGINE_H
#include "base/atomic.hpp"
#include "base/debug.hpp" #include "base/debug.hpp"
#include "base/exception.hpp" #include "base/exception.hpp"
#include "base/lazy-init.hpp" #include "base/lazy-init.hpp"
#include "base/logger.hpp" #include "base/logger.hpp"
#include "base/shared.hpp"
#include "base/shared-object.hpp" #include "base/shared-object.hpp"
#include <atomic> #include <atomic>
#include <exception> #include <exception>
@ -174,21 +176,29 @@ public:
template<class OnTimeout> template<class OnTimeout>
Timeout(boost::asio::io_context::strand& strand, const Timer::duration_type& timeoutFromNow, OnTimeout onTimeout) Timeout(boost::asio::io_context::strand& strand, const Timer::duration_type& timeoutFromNow, OnTimeout onTimeout)
: m_Timer(strand.context(), timeoutFromNow) : m_Timer(strand.context(), timeoutFromNow), m_Cancelled(Shared<Atomic<bool>>::Make(false))
{ {
VERIFY(strand.running_in_this_thread()); VERIFY(strand.running_in_this_thread());
m_Timer.async_wait(boost::asio::bind_executor(strand, [onTimeout = std::move(onTimeout)](boost::system::error_code ec) { m_Timer.async_wait(boost::asio::bind_executor(
if (!ec) { strand, [cancelled = m_Cancelled, onTimeout = std::move(onTimeout)](boost::system::error_code ec) {
onTimeout(); if (!ec && !cancelled->load()) {
onTimeout();
}
} }
})); ));
}
~Timeout() override
{
Cancel();
} }
void Cancel(); void Cancel();
private: private:
Timer m_Timer; Timer m_Timer;
Shared<Atomic<bool>>::Ptr m_Cancelled;
}; };
} }

View File

@ -5,6 +5,7 @@
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include <BoostTestTargetConfig.h> #include <BoostTestTargetConfig.h>
#include <thread>
using namespace icinga; using namespace icinga;
@ -30,7 +31,10 @@ BOOST_AUTO_TEST_CASE(timeout_run)
timer.async_wait(yc); timer.async_wait(yc);
}); });
std::thread eventLoop ([&io] { io.run(); });
io.run(); io.run();
eventLoop.join();
BOOST_CHECK_EQUAL(called, 1); BOOST_CHECK_EQUAL(called, 1);
} }
@ -54,7 +58,10 @@ BOOST_AUTO_TEST_CASE(timeout_cancelled)
timer.async_wait(yc); timer.async_wait(yc);
}); });
std::thread eventLoop ([&io] { io.run(); });
io.run(); io.run();
eventLoop.join();
BOOST_CHECK_EQUAL(called, 0); BOOST_CHECK_EQUAL(called, 0);
} }
@ -80,7 +87,10 @@ BOOST_AUTO_TEST_CASE(timeout_scope)
timer.async_wait(yc); timer.async_wait(yc);
}); });
std::thread eventLoop ([&io] { io.run(); });
io.run(); io.run();
eventLoop.join();
BOOST_CHECK_EQUAL(called, 0); BOOST_CHECK_EQUAL(called, 0);
} }
@ -108,7 +118,10 @@ BOOST_AUTO_TEST_CASE(timeout_due_cancelled)
timer.async_wait(yc); timer.async_wait(yc);
}); });
std::thread eventLoop ([&io] { io.run(); });
io.run(); io.run();
eventLoop.join();
BOOST_CHECK_EQUAL(called, 0); BOOST_CHECK_EQUAL(called, 0);
} }
@ -136,7 +149,10 @@ BOOST_AUTO_TEST_CASE(timeout_due_scope)
timer.async_wait(yc); timer.async_wait(yc);
}); });
std::thread eventLoop ([&io] { io.run(); });
io.run(); io.run();
eventLoop.join();
BOOST_CHECK_EQUAL(called, 0); BOOST_CHECK_EQUAL(called, 0);
} }