From d3220b00b7134f114a7fc36e4de74cdaaa17d874 Mon Sep 17 00:00:00 2001 From: Denis Koronchik Date: Mon, 6 Oct 2014 15:10:37 +0300 Subject: [PATCH] [routing] Do osrm routing async. --- map/framework.cpp | 32 ++++++++------- map/routing_session.cpp | 14 ++++--- routing/osrm_router.cpp | 90 ++++++++++++++++++++++++++++------------- routing/osrm_router.hpp | 11 ++++- std/atomic.hpp | 15 +++++++ 5 files changed, 113 insertions(+), 49 deletions(-) create mode 100644 std/atomic.hpp diff --git a/map/framework.cpp b/map/framework.cpp index 607b170c2f..9b7f3cb56b 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -1865,22 +1865,24 @@ void Framework::BuildRoute(m2::PointD const & destination) if (IsRoutingActive()) CloseRouting(); - m_routingSession.BuildRoute(state->Position(), destination, [&] (Route const & route, IRouter::ResultCode code) - { - if (code == IRouter::NoError) + m_routingSession.BuildRoute(state->Position(), destination, + // Capture all dependent state by value! Functor is passed for async calculation and called in UI thread. + [this, state] (Route const & route, IRouter::ResultCode code) { - InsertRoute(route); - state->RouteBuilded(); - ShowRectExVisibleScale(route.GetPoly().GetLimitRect()); - } - else - { - RemoveRoute(); - ///@TODO resolve message about this error - string messageID = "route_build_failed_reason"; - ShowDialog(messageID, DialogOptions::Ok); - } - }); + if (code == IRouter::NoError) + { + InsertRoute(route); + state->RouteBuilded(); + ShowRectExVisibleScale(route.GetPoly().GetLimitRect()); + } + else + { + RemoveRoute(); + ///@TODO resolve message about this error + string messageID = "route_build_failed_reason"; + ShowDialog(messageID, DialogOptions::Ok); + } + }); } void Framework::FollowRoute() diff --git a/map/routing_session.cpp b/map/routing_session.cpp index 62e0b9ebff..72204f239c 100644 --- a/map/routing_session.cpp +++ b/map/routing_session.cpp @@ -35,13 +35,15 @@ void RoutingSession::RebuildRoute(m2::PointD const & startPoint, TReadyCallbackF Reset(); m_state = RouteNotReady; - m_router->CalculateRoute(startPoint, [&] (Route & route, IRouter::ResultCode e) - { - if (e == IRouter::NoError) - AssignRoute(route); + m_router->CalculateRoute(startPoint, + // Capture all dependent state by value! Functor is passed for async calculation and called in UI thread. + [this, callback] (Route & route, IRouter::ResultCode e) + { + if (e == IRouter::NoError) + AssignRoute(route); - callback(m_route, e); - }); + callback(m_route, e); + }); } bool RoutingSession::IsActive() const diff --git a/routing/osrm_router.cpp b/routing/osrm_router.cpp index 168f7ff63f..63befcd5bb 100644 --- a/routing/osrm_router.cpp +++ b/routing/osrm_router.cpp @@ -169,7 +169,7 @@ public: OsrmRouter::OsrmRouter(Index const * index, CountryFileFnT const & fn) - : m_countryFn(fn), m_pIndex(index) + : m_countryFn(fn), m_pIndex(index), m_isFinalChanged(false), m_isReadyThread(false) { } @@ -180,44 +180,80 @@ string OsrmRouter::GetName() const void OsrmRouter::SetFinalPoint(m2::PointD const & finalPt) { + threads::MutexGuard guard(m_paramsMutex); + UNUSED_VALUE(guard); + m_finalPt = finalPt; - m_cachedFinalNodes.clear(); + m_isFinalChanged = true; } -void OsrmRouter::CalculateRoute(m2::PointD const & startingPt, ReadyCallback const & callback) +void OsrmRouter::CalculateRoute(m2::PointD const & startPt, ReadyCallback const & callback) { + GetPlatform().RunAsync(bind(&OsrmRouter::CalculateRouteAsync, this, startPt, callback)); +} + +void OsrmRouter::CalculateRouteAsync(m2::PointD const & startPt, ReadyCallback const & callback) +{ + if (m_isReadyThread.test_and_set()) + return; + Route route(GetName()); ResultCode code; - try { - code = CalculateRouteImpl(startingPt, m_finalPt, route); - switch (code) - { - case StartPointNotFound: - LOG(LWARNING, ("Can't find start point node")); - break; - case EndPointNotFound: - LOG(LWARNING, ("Can't find end point node")); - break; - case PointsInDifferentMWM: - LOG(LWARNING, ("Points are in different MWMs")); - break; - case RouteNotFound: - LOG(LWARNING, ("Route not found")); - break; + threads::MutexGuard guard(m_routeMutex); + UNUSED_VALUE(guard); - default: - break; + m_isReadyThread.clear(); + + m2::PointD finalPt; + { + threads::MutexGuard params(m_paramsMutex); + UNUSED_VALUE(params); + + finalPt = m_finalPt; + + if (m_isFinalChanged) + m_cachedFinalNodes.clear(); + m_isFinalChanged = false; + } + + try + { + code = CalculateRouteImpl(startPt, finalPt, route); + switch (code) + { + case StartPointNotFound: + LOG(LWARNING, ("Can't find start point node")); + break; + case EndPointNotFound: + LOG(LWARNING, ("Can't find end point node")); + break; + case PointsInDifferentMWM: + LOG(LWARNING, ("Points are in different MWMs")); + break; + case RouteNotFound: + LOG(LWARNING, ("Route not found")); + break; + + default: + break; + } + } + catch (Reader::Exception const & e) + { + LOG(LERROR, ("Routing index absent or incorrect. Error while loading routing index:", e.Msg())); + code = InternalError; + + // Clear data while m_container is valid. + m_dataFacade.Clear(); + m_mapping.Clear(); + + m_container.Close(); } } - catch (Reader::Exception const & e) - { - LOG(LERROR, ("Routing index absent or incorrect. Error while loading routing index:", e.Msg())); - code = InternalError; - } - callback(route, code); + GetPlatform().RunOnGuiThread(bind(callback, route, code)); } namespace diff --git a/routing/osrm_router.hpp b/routing/osrm_router.hpp index d1946cf9c8..e2a41d74cf 100644 --- a/routing/osrm_router.hpp +++ b/routing/osrm_router.hpp @@ -4,7 +4,10 @@ #include "osrm2feature_map.hpp" #include "osrm_data_facade.hpp" +#include "../base/mutex.hpp" + #include "../std/function.hpp" +#include "../std/atomic.hpp" #include "../3party/osrm/osrm-backend/DataStructures/QueryEdge.h" @@ -36,7 +39,7 @@ public: virtual string GetName() const; virtual void SetFinalPoint(m2::PointD const & finalPt); - virtual void CalculateRoute(m2::PointD const & startingPt, ReadyCallback const & callback); + virtual void CalculateRoute(m2::PointD const & startPt, ReadyCallback const & callback); protected: IRouter::ResultCode FindPhantomNodes(string const & fName, m2::PointD const & startPt, m2::PointD const & finalPt, @@ -44,6 +47,7 @@ protected: bool NeedReload(string const & fPath) const; + void CalculateRouteAsync(m2::PointD const & startPt, ReadyCallback const & callback); ResultCode CalculateRouteImpl(m2::PointD const & startPt, m2::PointD const & finalPt, Route & route); private: @@ -55,7 +59,12 @@ private: FilesMappingContainer m_container; + bool m_isFinalChanged; FeatureGraphNodeVecT m_cachedFinalNodes; + + threads::Mutex m_paramsMutex; + threads::Mutex m_routeMutex; + atomic_flag m_isReadyThread; }; } diff --git a/std/atomic.hpp b/std/atomic.hpp new file mode 100644 index 0000000000..0e479ffa0a --- /dev/null +++ b/std/atomic.hpp @@ -0,0 +1,15 @@ +#pragma once +#include "common_defines.hpp" + +#ifdef new +#undef new +#endif + +#include + +using std::atomic; +using std::atomic_flag; + +#ifdef DEBUG_NEW +#define new DEBUG_NEW +#endif