From: Mikko Rasa Date: Tue, 3 Feb 2015 21:47:17 +0000 (+0200) Subject: Make route planning threaded X-Git-Url: http://git.tdb.fi/?p=r2c2.git;a=commitdiff_plain;h=bf321305d7bf65aa5033a835f61370cd48f54619 Make route planning threaded It can take several seconds in some cases, which would cause an unacceptable pause in simulation and control. --- diff --git a/source/libr2c2/trainrouteplanner.cpp b/source/libr2c2/trainrouteplanner.cpp index 7ee655a..b4f01ab 100644 --- a/source/libr2c2/trainrouteplanner.cpp +++ b/source/libr2c2/trainrouteplanner.cpp @@ -14,7 +14,9 @@ using namespace Msp; namespace R2C2 { TrainRoutePlanner::TrainRoutePlanner(Layout &layout): - result(PENDING) + goal(0), + result(PENDING), + thread(0) { const map &trains = layout.get_trains(); for(map::const_iterator i=trains.begin(); i!=trains.end(); ++i) @@ -25,38 +27,40 @@ TrainRoutePlanner::TrainRoutePlanner(Layout &layout): } } -void TrainRoutePlanner::plan() +TrainRoutePlanner::~TrainRoutePlanner() { - steps.clear(); - queue.clear(); - result = PENDING; + delete thread; +} - queue.push_back(RoutingStep()); - RoutingStep &start = queue.back(); - for(vector::iterator i=routed_trains.begin(); i!=routed_trains.end(); ++i) - start.trains.push_back(TrainRoutingState(*i)); - start.update_estimate(); +TrainRoutePlanner::Result TrainRoutePlanner::plan() +{ + prepare_plan(); + create_plan(); + if(result==PENDING) + finalize_plan(); - const RoutingStep *goal = 0; - while(!queue.empty()) - { - const RoutingStep &step = get_step(); - if(step.is_goal()) - { - goal = &step; - break; - } + return result; +} - add_steps(step); - } +void TrainRoutePlanner::plan_async() +{ + if(thread) + throw logic_error("already planning"); + + prepare_plan(); + thread = new PlanningThread(*this); +} - if(goal) +TrainRoutePlanner::Result TrainRoutePlanner::check() +{ + if(result==PENDING && goal) { - create_routes(*goal); - result = COMPLETE; + finalize_plan(); + delete thread; + thread = 0; } - else - result = FAILED; + + return result; } const list &TrainRoutePlanner::get_routes_for(const Train &train) const @@ -84,6 +88,37 @@ const TrainRoutePlanner::RoutingStep &TrainRoutePlanner::get_step() return steps.back(); } +void TrainRoutePlanner::prepare_plan() +{ + steps.clear(); + queue.clear(); + goal = 0; + result = PENDING; + + queue.push_back(RoutingStep()); + RoutingStep &start = queue.back(); + for(vector::iterator i=routed_trains.begin(); i!=routed_trains.end(); ++i) + start.trains.push_back(TrainRoutingState(*i)); + start.update_estimate(); +} + +void TrainRoutePlanner::create_plan() +{ + while(!queue.empty()) + { + const RoutingStep &step = get_step(); + if(step.is_goal()) + { + goal = &step; + return; + } + + add_steps(step); + } + + result = FAILED; +} + void TrainRoutePlanner::add_steps(const RoutingStep &step) { list new_steps; @@ -92,7 +127,7 @@ void TrainRoutePlanner::add_steps(const RoutingStep &step) queue.merge(new_steps); } -void TrainRoutePlanner::create_routes(const RoutingStep &goal) +void TrainRoutePlanner::finalize_plan() { for(vector::iterator i=routed_trains.begin(); i!=routed_trains.end(); ++i) { @@ -104,7 +139,7 @@ void TrainRoutePlanner::create_routes(const RoutingStep &goal) map sequenced_tracks; unsigned sequence = steps.size(); - for(const RoutingStep *i=&goal; i; i=i->prev) + for(const RoutingStep *i=goal; i; i=i->prev) for(vector::const_iterator j=i->trains.begin(); j!=i->trains.end(); ++j) { Track **history = j->info->track_history; @@ -166,6 +201,8 @@ void TrainRoutePlanner::create_routes(const RoutingStep &goal) --sequence; } } + + result = COMPLETE; } @@ -548,4 +585,16 @@ bool TrainRoutePlanner::RoutingStep::operator<(const RoutingStep &other) const return cost_estimate #include +#include #include #include "trackiter.h" #include "trainrouter.h" @@ -112,23 +113,42 @@ private: bool operator<(const RoutingStep &) const; }; + class PlanningThread: public Msp::Thread + { + private: + TrainRoutePlanner &planner; + + public: + PlanningThread(TrainRoutePlanner &); + + private: + virtual void main(); + }; + std::vector routed_trains; std::list steps; std::list queue; + const RoutingStep *goal; Result result; + PlanningThread *thread; public: TrainRoutePlanner(Layout &); + ~TrainRoutePlanner(); - void plan(); + Result plan(); + void plan_async(); + Result check(); Result get_result() { return result; } const std::list &get_routes_for(const Train &) const; const std::list &get_sequence_for(const Train &) const; private: const TrainRoutingInfo &get_train_info(const Train &) const; const RoutingStep &get_step(); + void prepare_plan(); + void create_plan(); void add_steps(const RoutingStep &); - void create_routes(const RoutingStep &); + void finalize_plan(); }; } // namespace R2C2 diff --git a/source/libr2c2/trainrouter.cpp b/source/libr2c2/trainrouter.cpp index 1c05f82..bbb87ea 100644 --- a/source/libr2c2/trainrouter.cpp +++ b/source/libr2c2/trainrouter.cpp @@ -222,7 +222,7 @@ void TrainRouter::tick(const Time::TimeDelta &dt) if(destination_changed && !planner) start_planning(train.get_layout()); - if(planner && planner->get_result()!=TrainRoutePlanner::PENDING) + if(planner && planner->check()!=TrainRoutePlanner::PENDING) { destination_changed = false; if(planner->get_result()==TrainRoutePlanner::COMPLETE) @@ -494,7 +494,7 @@ void TrainRouter::start_planning(Layout &layout) router->planner = planner; } - planner->plan(); + planner->plan_async(); }