Eclipse SUMO - Simulation of Urban MObility
GUIRunThread.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
20 // The thread that runs the simulation
21 /****************************************************************************/
22 #include <config.h>
23 
24 #include <cassert>
25 #include <string>
26 #include <iostream>
27 #include <algorithm>
28 
29 #include <guisim/GUINet.h>
33 #include "GUIApplicationWindow.h"
34 #include "GUIRunThread.h"
35 #include "GUIGlobals.h"
39 #include <utils/common/SysUtils.h>
45 #include <libsumo/Simulation.h>
46 
47 
48 // ===========================================================================
49 // member method definitions
50 // ===========================================================================
51 GUIRunThread::GUIRunThread(FXApp* app, MFXInterThreadEventClient* parent, double& simDelay,
53  MFXSingleEventThread(app, parent),
54  myNet(nullptr),
55  myHalting(true),
56  myQuit(false),
57  mySimulationInProgress(false),
58  myOk(true),
59  myHaveSignaledEnd(false),
60  mySimDelay(simDelay),
61  myEventQue(eq),
62  myEventThrow(ev),
63  myLastEndMillis(-1),
64  myLastBreakMillis(0),
65  myAmLibsumo(false) {
69 }
70 
71 
73  // the thread shall stop
74  myQuit = true;
75  deleteSim();
76  delete myErrorRetriever;
77  delete myMessageRetriever;
78  delete myWarningRetriever;
79  // wait for the thread
80  while (mySimulationInProgress || myNet != nullptr);
81 }
82 
83 
84 bool
86  assert(net != 0);
87  // assign new values
88  myOk = true;
89  myNet = net;
90  mySimStartTime = start;
91  mySimEndTime = end;
92  myHaveSignaledEnd = false;
93  // register message callbacks
96  if (!OptionsCont::getOptions().getBool("no-warnings")) {
98  }
99  // preload the routes especially for TraCI
100  mySimulationLock.lock();
101  try {
102  net->setCurrentTimeStep(start);
103  net->loadRoutes();
104  } catch (ProcessError& e2) {
105  if (std::string(e2.what()) != std::string("Process Error") && std::string(e2.what()) != std::string("")) {
106  WRITE_ERROR(e2.what());
107  }
108  MsgHandler::getErrorInstance()->inform(TL("Quitting (on error)."), false);
109  myHalting = true;
110  myOk = false;
111  mySimulationInProgress = false;
112 #ifndef _DEBUG
113  } catch (...) {
114  MsgHandler::getErrorInstance()->inform(TL("Quitting (on error)."), false);
115  myHalting = true;
116  myOk = false;
117  mySimulationInProgress = false;
118 #endif
119  }
120  mySimulationLock.unlock();
121  return myOk;
122 }
123 
124 
125 FXint
127  // perform an endless loop
128  while (!myQuit) {
129  if (myAmLibsumo) {
130  myApp->run();
131  } else {
132  // if the simulation shall be performed, do it
133  tryStep();
134  }
135  }
136  // delete a maybe existing simulation at the end
137  deleteSim();
138  return 0;
139 }
140 
141 
142 void
144  if (!myHalting && myNet != nullptr && myOk) {
145  const long beg = SysUtils::getCurrentMillis();
146  if (myLastEndMillis != -1) {
147  getNet().setIdleDuration((int)(beg - myLastEndMillis));
148  }
149  // check whether we shall stop at this step
150  myBreakpointLock.lock();
151  const bool haltAfter = std::find(myBreakpoints.begin(), myBreakpoints.end(), myNet->getCurrentTimeStep()) != myBreakpoints.end();
152  myBreakpointLock.unlock();
153  // stop after this step if wished
154  if (haltAfter) {
155  stop();
156  }
157  // stop the execution when only a single step should have been performed
158  if (mySingle) {
159  myHalting = true;
160  }
161  // do the step
162  makeStep();
164  // wait if wanted (delay is per simulated second)
165  long wait = (long)(mySimDelay * TS);
167  getNet().setSimDuration((int)(myLastEndMillis - beg));
168  wait -= (myLastEndMillis - beg);
169  if (wait > 0) {
171  sleep(wait);
172 #ifndef WIN32
173  } else if (myLastEndMillis - myLastBreakMillis > 1000) {
174  // ensure redraw event is successful at least once per second (#9028)
175  sleep(100);
177 #endif
178  }
179  } else {
180  // sleep if the simulation is not running
181  sleep(50);
182  }
183 }
184 
185 
186 void
188  GUIEvent* e = nullptr;
189  // simulation is being performed
190  mySimulationInProgress = true;
191  // execute a single step
192  try {
193  mySimulationLock.lock();
196  mySimulationLock.unlock();
197 
198  // inform parent that a step has been performed
199  e = new GUIEvent_SimulationStep();
202 
203  e = nullptr;
205  switch (state) {
213  // ensure that files are closed (deleteSim is called a bit later by the gui thread)
214  // MSNet destructor may trigger MsgHandler (via routing device cleanup). Closing output devices here is not safe
215  // OutputDevice::closeAll();
216  myHaveSignaledEnd = true;
217  }
218  break;
219  default:
220  break;
221  }
222  if (e != nullptr) {
225  myHalting = true;
226  }
227  // simulation step is over
228  mySimulationInProgress = false;
229  } catch (ProcessError& e2) {
230  if (std::string(e2.what()) != std::string("Process Error") && std::string(e2.what()) != std::string("")) {
231  WRITE_ERROR(e2.what());
232  }
233  MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
234  mySimulationLock.unlock();
235  mySimulationInProgress = false;
239  myHalting = true;
240  myOk = false;
241 #ifndef _DEBUG
242  } catch (...) {
243  MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
244  mySimulationLock.unlock();
245  mySimulationInProgress = false;
249  myHalting = true;
250  myOk = false;
251 #endif
252  }
253 }
254 
255 
256 void
258  mySingle = false;
259  myHalting = false;
260 }
261 
262 
263 void
265  mySingle = true;
266  myHalting = false;
267 }
268 
269 
270 void
272  // report the begin when wished
273  WRITE_MESSAGEF(TL("Simulation started with time: %."), time2string(mySimStartTime));
274  myOk = true;
275 }
276 
277 
278 void
280  mySingle = false;
281  myHalting = true;
282 }
283 
284 
285 bool
287  return myNet != nullptr;
288 }
289 
290 
291 void
293  myHalting = true;
294  // flush aggregated warnings
296  // remove message callbacks
300  //
301  mySimulationLock.lock();
302  if (myNet != nullptr) {
304  }
305  while (mySimulationInProgress) {
306  sleep(50);
307  }
308  delete myNet;
310  myNet = nullptr;
312  mySimulationLock.unlock();
314 }
315 
316 
317 GUINet&
319  return *myNet;
320 }
321 
322 
323 void
325  myHalting = true;
326  myQuit = true;
327 }
328 
329 
330 void
331 GUIRunThread::retrieveMessage(const MsgHandler::MsgType type, const std::string& msg) {
332  GUIEvent* e = new GUIEvent_Message(type, msg);
335 }
336 
337 
338 bool
340  return myNet != nullptr && myHalting;
341 }
342 
343 
344 bool
346  return myNet != nullptr && (!myHalting);
347 }
348 
349 
350 bool
352  return myNet != nullptr && myHalting;
353 }
354 
355 
356 void
359  if (mw != nullptr) {
360  for (GUIGlChildWindow* const window : mw->getViews()) {
361  window->getView()->waitForSnapshots(snapshotTime);
362  }
363  }
364 }
365 
366 
367 /****************************************************************************/
long long int SUMOTime
Definition: GUI.h:35
#define WRITE_MESSAGEF(...)
Definition: MsgHandler.h:298
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:304
#define TL(string)
Definition: MsgHandler.h:315
SUMOTime DELTA_T
Definition: SUMOTime.cpp:38
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition: SUMOTime.cpp:69
#define TS
Definition: SUMOTime.h:42
Event sent when the the simulation is over.
void clear()
Clears this container.
static GUIGlObjectStorage gIDStorage
A single static instance of this class.
const std::vector< GUIGlChildWindow * > & getViews() const
get views
static GUIMainWindow * getInstance()
get instance
A MSNet extended by some values for usage within the gui.
Definition: GUINet.h:82
void setIdleDuration(int val)
Sets the duration of the last step's idle part.
Definition: GUINet.cpp:456
void simulationStep()
Performs a single simulation step (locking the simulation)
Definition: GUINet.cpp:233
void setSimDuration(int val)
Sets the duration of the last step's simulation part.
Definition: GUINet.cpp:440
void guiSimulationStep()
Some further steps needed for gui processing.
Definition: GUINet.cpp:226
double & mySimDelay
simulation delay
Definition: GUIRunThread.h:175
void singleStep()
called when the user presses the "single step"-button
OutputDevice * myErrorRetriever
The instances of message retriever encapsulations.
Definition: GUIRunThread.h:172
GUINet * myNet
the loaded simulation network
Definition: GUIRunThread.h:145
SUMOTime mySimEndTime
Definition: GUIRunThread.h:148
FXMutex myBreakpointLock
Lock for modifying the list of breakpoints.
Definition: GUIRunThread.h:190
GUINet & getNet() const
returns the loaded network
std::vector< SUMOTime > myBreakpoints
List of breakpoints.
Definition: GUIRunThread.h:187
virtual FXint run()
starts the execution
virtual void begin()
starts the simulation (execution of one step after another)
void resume()
called when the user presses the "resume"-button
FXEX::MFXThreadEvent & myEventThrow
thrower events
Definition: GUIRunThread.h:181
virtual bool simulationIsStartable() const
check if simulation is startable
bool networkAvailable() const
returns the information whether a network has been loaded
bool myOk
flag to check if all is ok
Definition: GUIRunThread.h:162
virtual bool simulationIsStepable() const
check if simulation is stepable
bool mySimulationInProgress
information whether a simulation step is being performed
Definition: GUIRunThread.h:159
virtual bool init(GUINet *net, SUMOTime start, SUMOTime end)
initialises the thread with the new simulation
void makeStep()
make simulation step
bool myHalting
information whether the simulation is halting (is not being executed)
Definition: GUIRunThread.h:151
virtual ~GUIRunThread()
destructor
void tryStep()
try simulation step
virtual bool simulationIsStopable() const
check if simulation is stopableo
OutputDevice * myMessageRetriever
Definition: GUIRunThread.h:172
long myLastEndMillis
end of the last simulation step
Definition: GUIRunThread.h:193
bool mySingle
information whether the thread is running in single step mode
Definition: GUIRunThread.h:165
OutputDevice * myWarningRetriever
Definition: GUIRunThread.h:172
virtual void deleteSim()
deletes the existing simulation
void retrieveMessage(const MsgHandler::MsgType type, const std::string &msg)
Retrieves messages from the loading module.
void waitForSnapshots(const SUMOTime snapshotTime)
wait for snapshots
SUMOTime mySimStartTime
the times the simulation starts and ends with
Definition: GUIRunThread.h:148
bool myQuit
information whether the thread shall be stopped
Definition: GUIRunThread.h:155
void stop()
halts the simulation execution
bool myAmLibsumo
whether we are running in libsumo
Definition: GUIRunThread.h:199
void prepareDestruction()
halts the thread before it shall be deleted
long myLastBreakMillis
last time the simulation took a microsecond break for the fox event loop to catch up (#9028)
Definition: GUIRunThread.h:196
MFXSynchQue< GUIEvent * > & myEventQue
event queue
Definition: GUIRunThread.h:178
FXMutex mySimulationLock
mutex for lock simulation
Definition: GUIRunThread.h:184
GUIRunThread(FXApp *app, MFXInterThreadEventClient *mw, double &simDelay, MFXSynchQue< GUIEvent * > &eq, FXEX::MFXThreadEvent &ev)
constructor
bool myHaveSignaledEnd
whether the simulation already ended
Definition: GUIRunThread.h:168
static void sleep(long ms)
FXApp * myApp
pointer to APP
void push_back(T what)
Definition: MFXSynchQue.h:113
SimulationState adaptToState(const SimulationState state, const bool isLibsumo=false) const
Called after a simulation step, this method adapts the current simulation state if necessary.
Definition: MSNet.cpp:908
SimulationState
Possible states of a simulation - running or stopped with different reasons.
Definition: MSNet.h:94
@ SIMSTATE_TOO_MANY_TELEPORTS
The simulation had too many teleports.
Definition: MSNet.h:110
@ SIMSTATE_NO_FURTHER_VEHICLES
The simulation does not contain further vehicles.
Definition: MSNet.h:102
@ SIMSTATE_LOADING
The simulation is loading.
Definition: MSNet.h:96
@ SIMSTATE_ERROR_IN_SIM
An error occurred during the simulation step.
Definition: MSNet.h:106
@ SIMSTATE_CONNECTION_CLOSED
The connection to a client was closed by the client.
Definition: MSNet.h:104
@ SIMSTATE_END_STEP_REACHED
The final simulation step has been performed.
Definition: MSNet.h:100
static std::string getStateMessage(SimulationState state)
Returns the message to show if a certain state occurs.
Definition: MSNet.cpp:929
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:320
void closeSimulation(SUMOTime start, const std::string &reason="")
Closes the simulation (all files, connections, etc.)
Definition: MSNet.cpp:676
void setCurrentTimeStep(const SUMOTime step)
Sets the current simulation step (used by state loading)
Definition: MSNet.h:328
SimulationState simulationState(SUMOTime stopTime) const
This method returns the current simulation state. It should not modify status.
Definition: MSNet.cpp:878
void loadRoutes()
loads routes for the next few steps
Definition: MSNet.cpp:438
virtual void addRetriever(OutputDevice *retriever)
Adds a further retriever to the instance responsible for a certain msg type.
Definition: MsgHandler.cpp:237
static MsgHandler * getErrorInstance()
Returns the instance to add errors to.
Definition: MsgHandler.cpp:92
virtual void inform(std::string msg, bool addType=true)
adds a new error to the list
Definition: MsgHandler.cpp:154
static MsgHandler * getWarningInstance()
Returns the instance to add warnings to.
Definition: MsgHandler.cpp:79
virtual void clear(bool resetInformed=true)
Clears information whether an error occurred previously and print aggregated message summary.
Definition: MsgHandler.cpp:213
static void cleanupOnEnd()
Removes pending handler.
Definition: MsgHandler.cpp:359
virtual void removeRetriever(OutputDevice *retriever)
Removes the retriever from the handler.
Definition: MsgHandler.cpp:245
@ MT_MESSAGE
The message is only something to show.
@ MT_ERROR
The message is an error.
@ MT_WARNING
The message is a warning.
static MsgHandler * getMessageInstance()
Returns the instance to add normal messages to.
Definition: MsgHandler.cpp:66
Encapsulates an object's method for using it as a message retriever.
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:60
static void closeAll(bool keepErrorRetrievers=false)
static long getCurrentMillis()
Returns the current time in milliseconds.
Definition: SysUtils.cpp:44