Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/gui/GUIRunThread.cpp
169665 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 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
/****************************************************************************/
14
/// @file GUIRunThread.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Michael Behrisch
18
/// @date Sept 2002
19
///
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>
30
#include <utils/gui/events/GUIEvent_Message.h>
31
#include <utils/gui/events/GUIEvent_SimulationStep.h>
32
#include "GUIEvent_SimulationEnded.h"
33
#include "GUIApplicationWindow.h"
34
#include "GUIRunThread.h"
35
#include "GUIGlobals.h"
36
#include <microsim/MSVehicleControl.h>
37
#include <utils/options/OptionsCont.h>
38
#include <utils/options/OptionsIO.h>
39
#include <utils/common/SysUtils.h>
40
#include <utils/common/MsgRetrievingFunction.h>
41
#include <utils/common/MsgHandler.h>
42
#include <utils/common/UtilExceptions.h>
43
#include <utils/iodevices/OutputDevice.h>
44
#include <traci-server/TraCIServer.h>
45
#include <libsumo/Simulation.h>
46
47
48
// ===========================================================================
49
// member method definitions
50
// ===========================================================================
51
GUIRunThread::GUIRunThread(FXApp* app, MFXInterThreadEventClient* parent, double& simDelay,
52
MFXSynchQue<GUIEvent*>& eq, FXEX::MFXThreadEvent& ev) :
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) {
66
myErrorRetriever = new MsgRetrievingFunction<GUIRunThread>(this, &GUIRunThread::retrieveMessage, MsgHandler::MsgType::MT_ERROR);
67
myMessageRetriever = new MsgRetrievingFunction<GUIRunThread>(this, &GUIRunThread::retrieveMessage, MsgHandler::MsgType::MT_MESSAGE);
68
myWarningRetriever = new MsgRetrievingFunction<GUIRunThread>(this, &GUIRunThread::retrieveMessage, MsgHandler::MsgType::MT_WARNING);
69
}
70
71
72
GUIRunThread::~GUIRunThread() {
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
85
GUIRunThread::init(GUINet* net, SUMOTime start, SUMOTime end) {
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
94
MsgHandler::getErrorInstance()->addRetriever(myErrorRetriever);
95
MsgHandler::getMessageInstance()->addRetriever(myMessageRetriever);
96
if (!OptionsCont::getOptions().getBool("no-warnings")) {
97
MsgHandler::getWarningInstance()->addRetriever(myWarningRetriever);
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
126
GUIRunThread::run() {
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
143
GUIRunThread::tryStep() {
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();
163
waitForSnapshots(myNet->getCurrentTimeStep() - DELTA_T);
164
// wait if wanted (delay is per simulated second)
165
long wait = (long)(mySimDelay * TS);
166
myLastEndMillis = SysUtils::getCurrentMillis();
167
getNet().setSimDuration((int)(myLastEndMillis - beg));
168
wait -= (myLastEndMillis - beg);
169
if (wait > 0) {
170
myLastBreakMillis = myLastEndMillis;
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);
176
myLastBreakMillis = myLastEndMillis;
177
#endif
178
}
179
} else {
180
// sleep if the simulation is not running
181
sleep(50);
182
}
183
}
184
185
186
void
187
GUIRunThread::makeStep() {
188
GUIEvent* e = nullptr;
189
// simulation is being performed
190
mySimulationInProgress = true;
191
// execute a single step
192
try {
193
mySimulationLock.lock();
194
myNet->simulationStep();
195
myNet->guiSimulationStep();
196
mySimulationLock.unlock();
197
198
// inform parent that a step has been performed
199
e = new GUIEvent_SimulationStep();
200
myEventQue.push_back(e);
201
myEventThrow.signal();
202
203
e = nullptr;
204
MSNet::SimulationState state = myNet->adaptToState(myNet->simulationState(mySimEndTime), myAmLibsumo);
205
switch (state) {
206
case MSNet::SIMSTATE_LOADING:
207
case MSNet::SIMSTATE_END_STEP_REACHED:
208
case MSNet::SIMSTATE_NO_FURTHER_VEHICLES:
209
case MSNet::SIMSTATE_CONNECTION_CLOSED:
210
case MSNet::SIMSTATE_TOO_MANY_TELEPORTS:
211
if (!myHaveSignaledEnd || state != MSNet::SIMSTATE_END_STEP_REACHED) {
212
e = new GUIEvent_SimulationEnded(state, myNet->getCurrentTimeStep() - DELTA_T);
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) {
223
myEventQue.push_back(e);
224
myEventThrow.signal();
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;
236
e = new GUIEvent_SimulationEnded(MSNet::SIMSTATE_ERROR_IN_SIM, myNet->getCurrentTimeStep());
237
myEventQue.push_back(e);
238
myEventThrow.signal();
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;
246
e = new GUIEvent_SimulationEnded(MSNet::SIMSTATE_ERROR_IN_SIM, myNet->getCurrentTimeStep());
247
myEventQue.push_back(e);
248
myEventThrow.signal();
249
myHalting = true;
250
myOk = false;
251
#endif
252
}
253
}
254
255
256
void
257
GUIRunThread::resume() {
258
mySingle = false;
259
myHalting = false;
260
}
261
262
263
void
264
GUIRunThread::singleStep() {
265
mySingle = true;
266
myHalting = false;
267
}
268
269
270
void
271
GUIRunThread::begin() {
272
// report the begin when wished
273
WRITE_MESSAGEF(TL("Simulation started with time: %."), time2string(mySimStartTime));
274
myOk = true;
275
}
276
277
278
void
279
GUIRunThread::stop() {
280
mySingle = false;
281
myHalting = true;
282
}
283
284
285
bool
286
GUIRunThread::networkAvailable() const {
287
return myNet != nullptr;
288
}
289
290
291
void
292
GUIRunThread::deleteSim() {
293
myHalting = true;
294
// flush aggregated warnings
295
MsgHandler::getWarningInstance()->clear();
296
// remove message callbacks
297
MsgHandler::getErrorInstance()->removeRetriever(myErrorRetriever);
298
MsgHandler::getWarningInstance()->removeRetriever(myWarningRetriever);
299
MsgHandler::getMessageInstance()->removeRetriever(myMessageRetriever);
300
//
301
mySimulationLock.lock();
302
if (myNet != nullptr) {
303
myNet->closeSimulation(mySimStartTime, MSNet::getStateMessage(myNet->simulationState(mySimEndTime)));
304
}
305
while (mySimulationInProgress) {
306
sleep(50);
307
}
308
delete myNet;
309
GUIGlObjectStorage::gIDStorage.clear();
310
myNet = nullptr;
311
OutputDevice::closeAll();
312
mySimulationLock.unlock();
313
MsgHandler::cleanupOnEnd();
314
}
315
316
317
GUINet&
318
GUIRunThread::getNet() const {
319
return *myNet;
320
}
321
322
323
void
324
GUIRunThread::prepareDestruction() {
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);
333
myEventQue.push_back(e);
334
myEventThrow.signal();
335
}
336
337
338
bool
339
GUIRunThread::simulationIsStartable() const {
340
return myNet != nullptr && myHalting && myOk;
341
}
342
343
344
bool
345
GUIRunThread::simulationIsStopable() const {
346
return myNet != nullptr && (!myHalting);
347
}
348
349
350
bool
351
GUIRunThread::simulationIsStepable() const {
352
return myNet != nullptr && myHalting && myOk;
353
}
354
355
356
void
357
GUIRunThread::waitForSnapshots(const SUMOTime snapshotTime) {
358
GUIMainWindow* const mw = GUIMainWindow::getInstance();
359
if (mw != nullptr) {
360
for (GUIGlChildWindow* const window : mw->getViews()) {
361
window->getView()->waitForSnapshots(snapshotTime);
362
}
363
}
364
}
365
366
367
/****************************************************************************/
368
369