ThreadedLoopMacros.hpp
Go to the documentation of this file.
1 /*
2 
3  This file is part of OpenFLUID software
4  Copyright(c) 2007, INRA - Montpellier SupAgro
5 
6 
7  == GNU General Public License Usage ==
8 
9  OpenFLUID 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 3 of the License, or
12  (at your option) any later version.
13 
14  OpenFLUID 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 OpenFLUID. If not, see <http://www.gnu.org/licenses/>.
21 
22 
23  == Other Usage ==
24 
25  Other Usage means a use of OpenFLUID that is inconsistent with the GPL
26  license, and requires a written agreement between You and INRA.
27  Licensees for Other Usage of OpenFLUID may use this file in accordance
28  with the terms contained in the written agreement between You and INRA.
29 
30 */
31 
32 
33 /**
34  @file ThreadedLoopMacros.hpp
35 
36  @author Jean-Christophe FABRE <jean-christophe.fabre@supagro.inra.fr>
37  */
38 
39 
40 #ifndef __OPENFLUID_WARE_THREADEDLOOPMACROS_HPP__
41 #define __OPENFLUID_WARE_THREADEDLOOPMACROS_HPP__
42 
43 
44 #include <functional>
45 
46 #include <QtGlobal>
47 
48 #if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
49 #include <QtConcurrent>
50 #endif
51 
52 #include <QtConcurrentRun>
53 #include <QFutureSynchronizer>
54 
56 
57 
58 // =====================================================================
59 // =====================================================================
60 
61 
62 #define _THREADSYNCID(_id) _M_##_id##_Sync
63 
64 
65 #define _APPLY_UNITS_ORDERED_LOOP_THREADED_WITHID(id,unitsclass,funcptr,...) \
66  openfluid::core::UnitsList_t* _UNITSLISTID(id) = mp_SpatialData->spatialUnits(unitsclass)->list(); \
67  if (_UNITSLISTID(id) != nullptr) \
68  { \
69  openfluid::core::UnitsList_t::iterator _UNITSLISTITERID(id) = _UNITSLISTID(id)->begin(); \
70  if (_UNITSLISTITERID(id) != _UNITSLISTID(id)->end()) \
71  { \
72  openfluid::core::PcsOrd_t _PCSORDID(id) = _UNITSLISTITERID(id)->getProcessOrder(); \
73  while (_UNITSLISTITERID(id) != _UNITSLISTID(id)->end()) \
74  { \
75  QFutureSynchronizer<void> _THREADSYNCID(id); \
76  while (_UNITSLISTITERID(id) != _UNITSLISTID(id)->end() && \
77  _UNITSLISTITERID(id)->getProcessOrder() == _PCSORDID(id)) \
78  { \
79  try \
80  { \
81  _THREADSYNCID(id).addFuture(QtConcurrent::run(std::bind(&funcptr,\
82  this,\
83  &(*_UNITSLISTITERID(id)),## __VA_ARGS__)));\
84  if (_THREADSYNCID(id).futures().size() == OPENFLUID_GetSimulatorMaxThreads())\
85  { \
86  _THREADSYNCID(id).waitForFinished(); \
87  _THREADSYNCID(id).clearFutures(); \
88  }\
89  }\
90  catch (QtConcurrent::UnhandledException& E) \
91  { \
92  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION, \
93  "QtConcurrent::UnhandledException in threaded loop"); \
94  } \
95  ++_UNITSLISTITERID(id); \
96  } \
97  _THREADSYNCID(id).waitForFinished(); \
98  _THREADSYNCID(id).clearFutures(); \
99  if (_UNITSLISTITERID(id) != _UNITSLISTID(id)->end()) _PCSORDID(id) = _UNITSLISTITERID(id)->getProcessOrder(); \
100  } \
101  } \
102  }
103 
104 /**
105  Macro for applying a threaded simulator to each unit of a class, following their process order
106  @param[in] unitsclass name of the units class
107  @param[in] funcptr member simulator name
108  @param[in] ... extra parameters to pass to the member simulator
109 */
110 #define APPLY_UNITS_ORDERED_LOOP_THREADED(unitsclass,funcptr,...) \
111  _APPLY_UNITS_ORDERED_LOOP_THREADED_WITHID(__LINE__,unitsclass,funcptr,## __VA_ARGS__)
112 
113 
114 
115 #define _APPLY_ALLUNITS_ORDERED_LOOP_THREADED_WITHID(id,funcptr,...) \
116  openfluid::core::UnitsPtrList_t* _UNITSPTRLISTID(id) = mp_SpatialData->allSpatialUnits(); \
117  if (_UNITSPTRLISTID(id) != nullptr) \
118  { \
119  openfluid::core::UnitsPtrList_t::iterator _UNITSPTRLISTITERID(id) = _UNITSPTRLISTID(id)->begin(); \
120  if (_UNITSPTRLISTITERID(id) != _UNITSPTRLISTID(id)->end()) \
121  { \
122  openfluid::core::PcsOrd_t _PCSORDID(id) = (*_UNITSPTRLISTITERID(id))->getProcessOrder(); \
123  while (_UNITSPTRLISTITERID(id) != _UNITSPTRLISTID(id)->end()) \
124  { \
125  QFutureSynchronizer<void> _THREADSYNCID(id); \
126  while (_UNITSPTRLISTITERID(id) != _UNITSPTRLISTID(id)->end() && \
127  (*_UNITSPTRLISTITERID(id))->getProcessOrder() == _PCSORDID(id)) \
128  { \
129  try \
130  { \
131  _THREADSYNCID(id).addFuture(QtConcurrent::run(std::bind(&funcptr,\
132  this,\
133  (*_UNITSPTRLISTITERID(id)),## __VA_ARGS__)));\
134  if (_THREADSYNCID(id).futures().size() == OPENFLUID_GetSimulatorMaxThreads())\
135  { \
136  _THREADSYNCID(id).waitForFinished(); \
137  _THREADSYNCID(id).clearFutures(); \
138  }\
139  }\
140  catch(QtConcurrent::UnhandledException& E) \
141  { \
142  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION, \
143  "QtConcurrent::UnhandledException in threaded loop"); \
144  } \
145  ++_UNITSPTRLISTITERID(id); \
146  } \
147  _THREADSYNCID(id).waitForFinished(); \
148  _THREADSYNCID(id).clearFutures(); \
149  if (_UNITSPTRLISTITERID(id) != _UNITSPTRLISTID(id)->end())\
150  _PCSORDID(id) = (*_UNITSPTRLISTITERID(id))->getProcessOrder(); \
151  } \
152  } \
153  }
154 
155 /**
156  Macro for applying a threaded simulator to each unit of the domain, following their process order
157  @param[in] funcptr member simulator name
158  @param[in] ... extra parameters to pass to the member simulator
159 */
160 #define APPLY_ALLUNITS_ORDERED_LOOP_THREADED(funcptr,...) \
161  _APPLY_ALLUNITS_ORDERED_LOOP_THREADED_WITHID(__LINE__,funcptr,## __VA_ARGS__)
162 
163 
164 
165 
166 // =====================================================================
167 // =====================================================================
168 
169 
170 #endif /* __OPENFLUID_WARE_THREADEDLOOPMACROS_HPP__ */