source: src/Actions/ActionQueue.cpp@ 06b5df

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 06b5df was 06b5df, checked in by Frederik Heber <heber@…>, 11 years ago

FIX: CommandLineParser causes idling thread when parsing goes wrong.

  • CommandLineParser::Parse() now returns bool to give status of parsing, only when true is scanForArguments() called, which fills the ActionQueue's queue which is not executed anymore because the run thread was already stopped by the caught exception from the parse failure.
  • Property mode set to 100644
File size: 9.9 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2013 Frederik Heber. All rights reserved.
5 *
6 *
7 * This file is part of MoleCuilder.
8 *
9 * MoleCuilder is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * MoleCuilder is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/*
24 * ActionQueue.cpp
25 *
26 * Created on: Aug 16, 2013
27 * Author: heber
28 */
29
30// include config.h
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34
35#include "CodePatterns/MemDebug.hpp"
36
37#include "Actions/ActionQueue.hpp"
38
39#include "CodePatterns/Assert.hpp"
40#include "CodePatterns/IteratorAdaptors.hpp"
41#include "CodePatterns/Log.hpp"
42#include "CodePatterns/Singleton_impl.hpp"
43
44#include <boost/date_time/posix_time/posix_time.hpp>
45#include <boost/version.hpp>
46#include <string>
47#include <sstream>
48#include <vector>
49
50#include "Actions/ActionExceptions.hpp"
51#include "Actions/ActionHistory.hpp"
52#include "Actions/ActionRegistry.hpp"
53#include "World.hpp"
54
55using namespace MoleCuilder;
56
57const Action* ActionQueue::_lastchangedaction = NULL;
58
59ActionQueue::ActionQueue() :
60 Observable("ActionQueue"),
61 AR(new ActionRegistry()),
62 history(new ActionHistory),
63 CurrentAction(0),
64#ifndef HAVE_ACTION_THREAD
65 lastActionOk(true)
66#else
67 lastActionOk(true),
68 run_thread(boost::bind(&ActionQueue::run, this)),
69 run_thread_isIdle(true)
70#endif
71{
72 // channels of observable
73 Channels *OurChannel = new Channels;
74 NotificationChannels.insert( std::make_pair(static_cast<Observable *>(this), OurChannel) );
75 // add instance for each notification type
76 for (size_t type = 0; type < NotificationType_MAX; ++type)
77 OurChannel->addChannel(type);
78}
79
80ActionQueue::~ActionQueue()
81{
82#ifdef HAVE_ACTION_THREAD
83 stop();
84#endif
85
86 clearQueue();
87
88 delete history;
89 delete AR;
90}
91
92void ActionQueue::queueAction(const std::string &name, enum Action::QueryOptions state)
93{
94 const Action * const registryaction = AR->getActionByName(name);
95 queueAction(registryaction, state);
96}
97
98void ActionQueue::queueAction(const Action * const _action, enum Action::QueryOptions state)
99{
100 OBSERVE;
101 NOTIFY(ActionQueued);
102 Action *newaction = _action->clone(state);
103 newaction->prepare(state);
104#ifdef HAVE_ACTION_THREAD
105 mtx_queue.lock();
106#endif
107 actionqueue.push_back( newaction );
108#ifndef HAVE_ACTION_THREAD
109 try {
110 newaction->call();
111 lastActionOk = true;
112 } catch(ActionFailureException &e) {
113 std::cerr << "Action " << *boost::get_error_info<ActionNameString>(e) << " has failed." << std::endl;
114 World::getInstance().setExitFlag(5);
115 clearQueue();
116 lastActionOk = false;
117 std::cerr << "ActionQueue cleared." << std::endl;
118 } catch (std::exception &e) {
119 pushStatus("FAIL: General exception caught, aborting.");
120 World::getInstance().setExitFlag(134);
121 clearQueue();
122 lastActionOk = false;
123 std::cerr << "ActionQueue cleared." << std::endl;
124 }
125#else
126 {
127 boost::lock_guard<boost::mutex> lock(mtx_idle);
128 run_thread_isIdle = (CurrentAction == actionqueue.size());
129 }
130 mtx_queue.unlock();
131#endif
132 _lastchangedaction = newaction;
133}
134
135void ActionQueue::insertAction(Action *_action, enum Action::QueryOptions state)
136{
137#ifndef HAVE_ACTION_THREAD
138 queueAction(_action, state);
139#else
140 Action *newaction = _action->clone(state);
141 newaction->prepare(state);
142 mtx_queue.lock();
143 tempqueue.push_back( newaction );
144 {
145 boost::lock_guard<boost::mutex> lock(mtx_idle);
146 run_thread_isIdle = !((CurrentAction != actionqueue.size()) || !tempqueue.empty());
147 }
148 mtx_queue.unlock();
149#endif
150}
151
152#ifdef HAVE_ACTION_THREAD
153void ActionQueue::run()
154{
155 bool Interrupted = false;
156 do {
157 // sleep for some time and wait for queue to fill up again
158 try {
159#if BOOST_VERSION < 105000
160 run_thread.sleep(boost::get_system_time() + boost::posix_time::milliseconds(100));
161#else
162 boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
163#endif
164 } catch(boost::thread_interrupted &e) {
165 LOG(2, "INFO: ActionQueue has received stop signal.");
166 Interrupted = true;
167 }
168// LOG(1, "DEBUG: Start of ActionQueue's run() loop.");
169 // call all currently present Actions
170 mtx_queue.lock();
171 insertTempQueue();
172 bool status = (CurrentAction != actionqueue.size());
173 mtx_queue.unlock();
174 while (status) {
175 // boost::this_thread::disable_interruption di;
176 LOG(0, "Calling Action " << actionqueue[CurrentAction]->getName() << " ... ");
177 try {
178 actionqueue[CurrentAction]->call();
179 pushStatus("SUCCESS: Action "+actionqueue[CurrentAction]->getName()+" successful.");
180 lastActionOk = true;
181 } catch(ActionFailureException &e) {
182 pushStatus("FAIL: Action "+*boost::get_error_info<ActionNameString>(e)+" has failed.");
183 World::getInstance().setExitFlag(5);
184 clearQueue();
185 lastActionOk = false;
186 std::cerr << "ActionQueue cleared." << std::endl;
187 CurrentAction = (size_t)-1;
188 } catch (std::exception &e) {
189 pushStatus("FAIL: General exception caught, aborting.");
190 World::getInstance().setExitFlag(134);
191 clearQueue();
192 std::cerr << "ActionQueue cleared." << std::endl;
193 CurrentAction = (size_t)-1;
194 }
195 // access actionqueue, hence using mutex
196 mtx_queue.lock();
197 // step on to next action and check for end
198 CurrentAction++;
199 // insert new actions (before [CurrentAction]) if they have been spawned
200 // we must have an extra vector for this, as we cannot change actionqueue
201 // while an action instance is "in-use"
202 insertTempQueue();
203 status = (CurrentAction != actionqueue.size());
204 mtx_queue.unlock();
205 }
206 {
207 boost::lock_guard<boost::mutex> lock(mtx_idle);
208 run_thread_isIdle = !((CurrentAction != actionqueue.size()) || !tempqueue.empty());
209 }
210 cond_idle.notify_one();
211// LOG(1, "DEBUG: End of ActionQueue's run() loop.");
212 } while (!Interrupted);
213}
214#endif
215
216void ActionQueue::insertTempQueue()
217{
218 if (!tempqueue.empty()) {
219 ActionQueue_t::iterator InsertionIter = actionqueue.begin();
220 std::advance(InsertionIter, CurrentAction);
221 actionqueue.insert( InsertionIter, tempqueue.begin(), tempqueue.end() );
222 tempqueue.clear();
223 }
224}
225
226#ifdef HAVE_ACTION_THREAD
227void ActionQueue::wait()
228{
229 boost::unique_lock<boost::mutex> lock(mtx_idle);
230 while(!run_thread_isIdle)
231 {
232 cond_idle.wait(lock);
233 }
234}
235#endif
236
237#ifdef HAVE_ACTION_THREAD
238void ActionQueue::stop()
239{
240 // notify actionqueue thread that we wish to terminate
241 run_thread.interrupt();
242 // wait till it ends
243 run_thread.join();
244}
245#endif
246
247Action* ActionQueue::getActionByName(const std::string &name)
248{
249 return AR->getActionByName(name);
250}
251
252bool ActionQueue::isActionKnownByName(const std::string &name) const
253{
254 return AR->isActionPresentByName(name);
255}
256
257void ActionQueue::registerAction(Action *_action)
258{
259 AR->registerInstance(_action);
260}
261
262void ActionQueue::outputAsCLI(std::ostream &output) const
263{
264 for (ActionQueue_t::const_iterator iter = actionqueue.begin();
265 iter != actionqueue.end();
266 ++iter) {
267 // skip store-session in printed list
268 if ( ((*iter)->getName() != std::string("store-session"))
269 && ((*iter)->getName() != std::string("load-session"))) {
270 if (iter != actionqueue.begin())
271 output << " ";
272 (*iter)->outputAsCLI(output);
273 }
274 }
275 output << std::endl;
276}
277
278void ActionQueue::outputAsPython(std::ostream &output) const
279{
280 const std::string prefix("pyMoleCuilder");
281 output << "import " << prefix << std::endl;
282 output << "# ========================== Stored Session BEGIN ==========================" << std::endl;
283 for (ActionQueue_t::const_iterator iter = actionqueue.begin();
284 iter != actionqueue.end();
285 ++iter) {
286 // skip store-session in printed list
287 if ( ((*iter)->getName() != std::string("store-session"))
288 && ((*iter)->getName() != std::string("load-session")))
289 (*iter)->outputAsPython(output, prefix);
290 }
291 output << "# =========================== Stored Session END ===========================" << std::endl;
292}
293
294const ActionTrait& ActionQueue::getActionsTrait(const std::string &name) const
295{
296 // this const_cast is just required as long as we have a non-const getActionByName
297 const Action * const action = const_cast<ActionQueue *>(this)->getActionByName(name);
298 return action->Traits;
299}
300
301void ActionQueue::addElement(Action* _Action,ActionState::ptr _state)
302{
303 history->addElement(_Action, _state);
304}
305
306void ActionQueue::clear()
307{
308 history->clear();
309}
310
311void ActionQueue::clearQueue()
312{
313 // free all actions contained in actionqueue
314 for (ActionQueue_t::iterator iter = actionqueue.begin();
315 !actionqueue.empty(); iter = actionqueue.begin()) {
316 delete *iter;
317 actionqueue.erase(iter);
318 }
319 // free all actions contained in tempqueue
320 for (ActionQueue_t::iterator iter = tempqueue.begin();
321 !tempqueue.empty(); iter = tempqueue.begin()) {
322 delete *iter;
323 tempqueue.erase(iter);
324 }
325#ifdef HAVE_ACTION_THREAD
326 {
327 boost::unique_lock<boost::mutex> lock(mtx_idle);
328 run_thread_isIdle = true;
329 }
330#endif
331}
332
333const ActionQueue::ActionTokens_t ActionQueue::getListOfActions() const
334{
335 ActionTokens_t returnlist;
336
337 returnlist.insert(
338 returnlist.end(),
339 MapKeyConstIterator<ActionRegistry::const_iterator>(AR->getBeginIter()),
340 MapKeyConstIterator<ActionRegistry::const_iterator>(AR->getEndIter()));
341
342 return returnlist;
343}
344
345void ActionQueue::undoLast()
346{
347 history->undoLast();
348}
349
350void ActionQueue::redoLast()
351{
352 history->redoLast();
353}
354
355
356CONSTRUCT_SINGLETON(ActionQueue)
Note: See TracBrowser for help on using the repository browser.