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@inra.fr>
37 
38  @cond OpenFLUID:completion
39  {
40  "contexts" : ["SIMULATOR", "OBSERVER"],
41  "menupath" : ["Compute code", "Fortran integration"],
42  "title" : "Include ThreadedLoopMacros header",
43  "text" : "#include <openfluid/ware/ThreadedLoopMacros.hpp>"
44  }
45  @endcond
46 */
47 
48 
49 #ifndef __OPENFLUID_WARE_THREADEDLOOPMACROS_HPP__
50 #define __OPENFLUID_WARE_THREADEDLOOPMACROS_HPP__
51 
52 
53 #include <functional>
54 #include <thread>
55 #include <vector>
56 #include <system_error>
57 
59 
60 
61 // =====================================================================
62 // =====================================================================
63 
64 
65 #define _THREADGROUPID(_id) _M_##_id##_ThreadGroup
66 #define _THREADID(_id) _M_##_id##_Thread
67 
68 
69 // =====================================================================
70 // =====================================================================
71 
72 
73 #define _APPLY_UNITS_ORDERED_LOOP_THREADED_WITHID(id,unitsclass,funcptr,...) \
74  openfluid::core::UnitsList_t* _UNITSLISTID(id) = mp_SpatialData->spatialUnits(unitsclass)->list(); \
75  if (_UNITSLISTID(id) != nullptr) \
76  { \
77  openfluid::core::UnitsList_t::iterator _UNITSLISTITERID(id) = _UNITSLISTID(id)->begin(); \
78  if (_UNITSLISTITERID(id) != _UNITSLISTID(id)->end()) \
79  { \
80  openfluid::core::PcsOrd_t _PCSORDID(id) = _UNITSLISTITERID(id)->getProcessOrder(); \
81  while (_UNITSLISTITERID(id) != _UNITSLISTID(id)->end()) \
82  { \
83  std::vector<std::thread> _THREADGROUPID(id); \
84  while (_UNITSLISTITERID(id) != _UNITSLISTID(id)->end() && \
85  _UNITSLISTITERID(id)->getProcessOrder() == _PCSORDID(id)) \
86  { \
87  try \
88  { \
89  _THREADGROUPID(id).push_back(std::thread(std::bind(&funcptr,this,\
90  &(*_UNITSLISTITERID(id)),## __VA_ARGS__))); \
91  if (_THREADGROUPID(id).size() == (unsigned int)OPENFLUID_GetSimulatorMaxThreads()) \
92  { \
93  for (auto& _THREADID(id) : _THREADGROUPID(id)) \
94  _THREADID(id).join(); \
95  _THREADGROUPID(id).clear(); \
96  } \
97  } \
98  catch (std::system_error& E) \
99  { \
100  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION, \
101  "Error in threaded loop (" + std::string(E.what()) +")"); \
102  } \
103  ++_UNITSLISTITERID(id); \
104  } \
105  for (auto& _THREADID(id) : _THREADGROUPID(id)) \
106  _THREADID(id).join(); \
107  _THREADGROUPID(id).clear(); \
108  if (_UNITSLISTITERID(id) != _UNITSLISTID(id)->end()) \
109  _PCSORDID(id) = _UNITSLISTITERID(id)->getProcessOrder(); \
110  } \
111  } \
112  }
113 
114 /**
115  Macro for applying a threaded simulator to each unit of a class, following their process order
116  @param[in] unitsclass name of the units class
117  @param[in] funcptr member simulator name
118  @param[in] ... extra parameters to pass to the member simulator
119 
120  @cond OpenFLUID:completion
121  {
122  "contexts" : ["SIMULATOR", "OBSERVER"],
123  "menupath" : ["Compute code", "Loops"],
124  "title" : "Threaded ordered loop on spatial units of a class",
125  "text" : "APPLY_UNITS_ORDERED_LOOP_THREADED(\"%%SEL_START%%UnitsClass%%SEL_END%%\",FuncPtr)"
126  }
127  @endcond
128 */
129 #define APPLY_UNITS_ORDERED_LOOP_THREADED(unitsclass,funcptr,...) \
130  _APPLY_UNITS_ORDERED_LOOP_THREADED_WITHID(__LINE__,unitsclass,funcptr,## __VA_ARGS__)
131 
132 
133 // =====================================================================
134 // =====================================================================
135 
136 
137 #define _APPLY_ALLUNITS_ORDERED_LOOP_THREADED_WITHID(id,funcptr,...) \
138  openfluid::core::UnitsPtrList_t* _UNITSPTRLISTID(id) = mp_SpatialData->allSpatialUnits(); \
139  if (_UNITSPTRLISTID(id) != nullptr) \
140  { \
141  openfluid::core::UnitsPtrList_t::iterator _UNITSPTRLISTITERID(id) = _UNITSPTRLISTID(id)->begin(); \
142  if (_UNITSPTRLISTITERID(id) != _UNITSPTRLISTID(id)->end()) \
143  { \
144  openfluid::core::PcsOrd_t _PCSORDID(id) = (*_UNITSPTRLISTITERID(id))->getProcessOrder(); \
145  while (_UNITSPTRLISTITERID(id) != _UNITSPTRLISTID(id)->end()) \
146  { \
147  std::vector<std::thread> _THREADGROUPID(id); \
148  while (_UNITSPTRLISTITERID(id) != _UNITSPTRLISTID(id)->end() && \
149  (*_UNITSPTRLISTITERID(id))->getProcessOrder() == _PCSORDID(id)) \
150  { \
151  try \
152  { \
153  _THREADGROUPID(id).push_back(std::thread(std::bind(&funcptr,this,\
154  (*_UNITSPTRLISTITERID(id)),## __VA_ARGS__))); \
155  if (_THREADGROUPID(id).size() == (unsigned int)OPENFLUID_GetSimulatorMaxThreads()) \
156  { \
157  for (auto& _THREADID(id) : _THREADGROUPID(id)) \
158  _THREADID(id).join(); \
159  _THREADGROUPID(id).clear(); \
160  } \
161  }\
162  catch (std::system_error& E) \
163  { \
164  throw openfluid::base::FrameworkException(OPENFLUID_CODE_LOCATION, \
165  "Error in threaded loop (" + std::string(E.what()) +")"); \
166  } \
167  ++_UNITSPTRLISTITERID(id); \
168  } \
169  for (auto& _THREADID(id) : _THREADGROUPID(id)) \
170  _THREADID(id).join(); \
171  _THREADGROUPID(id).clear(); \
172  if (_UNITSPTRLISTITERID(id) != _UNITSPTRLISTID(id)->end())\
173  _PCSORDID(id) = (*_UNITSPTRLISTITERID(id))->getProcessOrder(); \
174  } \
175  } \
176  }
177 
178 /**
179  Macro for applying a threaded simulator to each unit of the domain, following their process order
180  @param[in] funcptr member simulator name
181  @param[in] ... extra parameters to pass to the member simulator
182 
183  @cond OpenFLUID:completion
184  {
185  "contexts" : ["SIMULATOR", "OBSERVER"],
186  "menupath" : ["Compute code", "Loops"],
187  "title" : "Threaded ordered loop on all spatial units",
188  "text" : "APPLY_ALLUNITS_ORDERED_LOOP_THREADED(%%SEL_START%%FuncPtr%%SEL_END%%)"
189  }
190  @endcond
191 */
192 #define APPLY_ALLUNITS_ORDERED_LOOP_THREADED(funcptr,...) \
193  _APPLY_ALLUNITS_ORDERED_LOOP_THREADED_WITHID(__LINE__,funcptr,## __VA_ARGS__)
194 
195 
196 // =====================================================================
197 // =====================================================================
198 
199 
200 #endif /* __OPENFLUID_WARE_THREADEDLOOPMACROS_HPP__ */