CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
OscarMTMasterThread.cc
Go to the documentation of this file.
2 
5 
9 
12 
15 
16 #include "HepPDT/ParticleDataTable.hh"
18 
19 #include "G4PhysicalVolumeStore.hh"
20 
22  m_pUseMagneticField(iConfig.getParameter<bool>("UseMagneticField")),
23  m_pDD(nullptr), m_pMF(nullptr), m_pTable(nullptr),
24  m_masterThreadState(ThreadState::NotExist),
25  m_masterCanProceed(false),
26  m_mainCanProceed(false),
27  m_firstRun(true),
28  m_stopped(false)
29 {
30  // Lock the mutex
31  std::unique_lock<std::mutex> lk(m_threadMutex);
32 
33  LogDebug("OscarMTMasterThread") << "Master thread: Creating master thread";
34 
35  // Create Genat4 master thread
36  m_masterThread = std::thread([&](){
38  // Initialization
39 
40  std::shared_ptr<RunManagerMT> runManagerMaster;
41  std::unique_ptr<CustomUIsession> uiSession;
42 
43  // Lock the mutex (i.e. wait until the creating thread has called cv.wait()
44  std::unique_lock<std::mutex> lk2(m_threadMutex);
45 
46  LogDebug("OscarMTMasterThread") << "Main thread: initializing RunManagerMT";
47 
48  //UIsession manager for message handling
49  uiSession.reset(new CustomUIsession());
50 
51  // Create the master run manager, and share it to the CMSSW thread
52  runManagerMaster = std::make_shared<RunManagerMT>(iConfig);
54 
55  LogDebug("OscarMTMasterThread") << "Master thread: RunManagerMT initialization finished";
56 
58  // State loop
59  bool isG4Alive = false;
60  while(true) {
61  // Signal main thread that it can proceed
62  m_mainCanProceed = true;
63  LogDebug("OscarMTMasterThread") << "Master thread: State loop, notify main thread";
64  m_notifyMainCv.notify_one();
65 
66  // Wait until the main thread sends signal
67  m_masterCanProceed = false;
68  LogDebug("OscarMTMasterThread") << "Master thread: State loop, starting wait";
69  m_notifyMasterCv.wait(lk2, [&]{return m_masterCanProceed;});
70 
71  // Act according to the state
72  LogDebug("OscarMTMasterThread") << "Master thread: Woke up, state is " << static_cast<int>(m_masterThreadState);
74  // Initialize Geant4
75  LogDebug("OscarMTMasterThread") << "Master thread: Initializing Geant4";
76  runManagerMaster->initG4(m_pDD, m_pMF, m_pTable);
77  isG4Alive = true;
78  }
80  // Stop Geant4
81  LogDebug("OscarMTMasterThread") << "Master thread: Stopping Geant4";
82  runManagerMaster->stopG4();
83  isG4Alive = false;
84  }
86  LogDebug("OscarMTMasterThread") << "Master thread: Breaking out of state loop";
87  if(isG4Alive)
88  throw cms::Exception("Assert") << "Geant4 is still alive, master thread state must be set to EndRun before Destruct";
89  break;
90  }
91  else {
92  throw cms::Exception("Assert") << "Illegal master thread state " << static_cast<int>(m_masterThreadState);
93  }
94  }
95 
97  // Cleanup
98  LogDebug("OscarMTMasterThread") << "Master thread: Am I unique owner of runManagerMaster? " << runManagerMaster.unique();
99 
100  // must be done in this thread, segfault otherwise
101  runManagerMaster.reset();
102  G4PhysicalVolumeStore::Clean();
103 
104  LogDebug("OscarMTMasterThread") << "Master thread: Reseted shared_ptr";
105  lk2.unlock();
106  LogDebug("OscarMTMasterThread") << "Master thread: Finished";
107  });
108 
109  // Start waiting a signal from the condition variable (releases the lock temporarily)
110  // First for initialization
111  m_mainCanProceed = false;
112  LogDebug("OscarMTMasterThread") << "Main thread: Signal master for initialization";
113  m_notifyMainCv.wait(lk, [&](){return m_mainCanProceed;});
114 
115  lk.unlock();
116  LogDebug("OscarMTMasterThread") << "Main thread: Finish constructor";
117 }
118 
120  if(!m_stopped) {
121  edm::LogError("OscarMTMasterThread") << "OscarMTMasterThread::stopThread() has not been called to stop Geant4 and join the master thread";
122  }
123 }
124 
126  std::lock_guard<std::mutex> lk(m_protectMutex);
127 
128  std::unique_lock<std::mutex> lk2(m_threadMutex);
129 
130  // Reading from ES must be done in the main (CMSSW) thread
131  readES(iSetup);
132 
134  m_masterCanProceed = true;
135  m_mainCanProceed = false;
136  LogDebug("OscarMTMasterThread") << "Main thread: Signal master for BeginRun";
137  m_notifyMasterCv.notify_one();
138  m_notifyMainCv.wait(lk2, [&](){return m_mainCanProceed;});
139 
140  lk2.unlock();
141  LogDebug("OscarMTMasterThread") << "Main thread: Finish beginRun";
142 }
143 
145  std::lock_guard<std::mutex> lk(m_protectMutex);
146 
147  std::unique_lock<std::mutex> lk2(m_threadMutex);
149  m_mainCanProceed = false;
150  m_masterCanProceed = true;
151  LogDebug("OscarMTMasterThread") << "Main thread: signal master thread for EndRun";
152  m_notifyMasterCv.notify_one();
153  m_notifyMainCv.wait(lk2, [&](){return m_mainCanProceed;});
154  lk2.unlock();
155  LogDebug("OscarMTMasterThread") << "Main thread: Finish endRun";
156 }
157 
159  if(m_stopped) {
160  edm::LogError("OscarMTMasterThread") << "Second call to OscarMTMasterThread::stopThread(), not doing anything";
161  return;
162  }
163  LogDebug("OscarMTMasterThread") << "Main thread: stopThread()";
164 
165  // Release our instance of the shared master run manager, so that
166  // the G4 master thread can do the cleanup. Then notify the master
167  // thread, and join it.
168  std::unique_lock<std::mutex> lk2(m_threadMutex);
169  m_runManagerMaster.reset();
170  LogDebug("OscarMTMasterThread") << "Main thread: reseted shared_ptr";
171 
173  m_masterCanProceed = true;
174  LogDebug("OscarMTMasterThread") << "Main thread: signal master thread for Destruct";
175  m_notifyMasterCv.notify_one();
176  lk2.unlock();
177 
178  LogDebug("OscarMTMasterThread") << "Main thread: joining master thread";
179  m_masterThread.join();
180  LogDebug("OscarMTMasterThread") << "Main thread: finished";
181  m_stopped = true;
182 }
183 
184 void OscarMTMasterThread::readES(const edm::EventSetup& iSetup) const {
185  bool geomChanged = idealGeomRcdWatcher_.check(iSetup);
186  if (geomChanged && (!m_firstRun)) {
187  throw cms::Exception("BadConfig")
188  << "[SimG4Core OscarMTMasterThread]\n"
189  << "The Geometry configuration is changed during the job execution\n"
190  << "this is not allowed, the geometry must stay unchanged\n";
191  }
192  if (m_pUseMagneticField) {
193  bool magChanged = idealMagRcdWatcher_.check(iSetup);
194  if (magChanged && (!m_firstRun)) {
195  throw cms::Exception("BadConfig")
196  << "[SimG4Core OscarMTMasterThread]\n"
197  << "The MagneticField configuration is changed during the job execution\n"
198  << "this is not allowed, the MagneticField must stay unchanged\n";
199  }
200  }
201  // Don't read from ES if not the first run, just as in
202  // RunManager::initG4()
203  if(!m_firstRun)
204  return;
205 
206  // DDDWorld: get the DDCV from the ES and use it to build the World
208  iSetup.get<IdealGeometryRecord>().get(pDD);
209  m_pDD = pDD.product();
210 
211  if(m_pUseMagneticField) {
213  iSetup.get<IdealMagneticFieldRecord>().get(pMF);
214  m_pMF = pMF.product();
215  }
216 
218  iSetup.get<PDTRecord>().get(fTable);
219  m_pTable = fTable.product();
220 
221  m_firstRun = false;
222 }
#define LogDebug(id)
std::shared_ptr< RunManagerMT > m_runManagerMaster
edm::ESWatcher< IdealGeometryRecord > idealGeomRcdWatcher_
#define nullptr
const RunManagerMT & runManagerMaster() const
ThreadState m_masterThreadState
void beginRun(const edm::EventSetup &iSetup) const
std::condition_variable m_notifyMasterCv
void readES(const edm::EventSetup &iSetup) const
const DDCompactView * m_pDD
const T & get() const
Definition: EventSetup.h:55
T const * product() const
Definition: ESHandle.h:86
OscarMTMasterThread(const edm::ParameterSet &iConfig)
T const * product() const
bool check(const edm::EventSetup &iSetup)
Definition: ESWatcher.h:57
edm::ESWatcher< IdealMagneticFieldRecord > idealMagRcdWatcher_
volatile std::atomic< bool > shutdown_flag false
const MagneticField * m_pMF
const HepPDT::ParticleDataTable * m_pTable
std::condition_variable m_notifyMainCv