Generated on for Gecode by doxygen 1.17.0
engine.hpp
Go to the documentation of this file.
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2/*
3 * Main authors:
4 * Christian Schulte <schulte@gecode.dev>
5 *
6 * Contributing authors:
7 * Mikael Zayenz Lagerkvist <lagerkvist@gecode.dev>
8 *
9 * Copyright:
10 * Christian Schulte, 2009
11 * Mikael Zayenz Lagerkvist, 2026
12 *
13 * This file is part of Gecode, the generic constraint
14 * development environment:
15 * http://www.gecode.dev
16 *
17 * Permission is hereby granted, free of charge, to any person obtaining
18 * a copy of this software and associated documentation files (the
19 * "Software"), to deal in the Software without restriction, including
20 * without limitation the rights to use, copy, modify, merge, publish,
21 * distribute, sublicense, and/or sell copies of the Software, and to
22 * permit persons to whom the Software is furnished to do so, subject to
23 * the following conditions:
24 *
25 * The above copyright notice and this permission notice shall be
26 * included in all copies or substantial portions of the Software.
27 *
28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 *
36 */
37
38namespace Gecode { namespace Search { namespace Par {
39
40
41 /*
42 * Basic access routines
43 */
44 template<class Tracer>
45 forceinline Engine<Tracer>&
47 return _engine;
48 }
49 template<class Tracer>
50 forceinline const Options&
51 Engine<Tracer>::opt(void) const {
52 return _opt;
53 }
54 template<class Tracer>
55 forceinline unsigned int
57 return static_cast<unsigned int>(opt().threads);
58 }
59 template<class Tracer>
60 forceinline bool
62 return has_stopped.load(std::memory_order_acquire);
63 }
64
65
66
67 /*
68 * Engine: command and wait handling
69 */
70 template<class Tracer>
71 forceinline typename Engine<Tracer>::Cmd
72 Engine<Tracer>::cmd(void) const {
73 return _cmd.load(std::memory_order_acquire);
74 }
75 template<class Tracer>
76 forceinline void
78 _cmd.store(C_WAIT, std::memory_order_release);
80 }
81 template<class Tracer>
82 forceinline void
84 _cmd.store(c, std::memory_order_release);
86 }
87 template<class Tracer>
88 forceinline void
90 _m_wait.acquire(); _m_wait.release();
91 }
92
93
94 /*
95 * Engine: initialization
96 */
97 template<class Tracer>
98 forceinline
100 : tracer(e.opt().tracer), _engine(e),
101 path(s == nullptr ? 0 : e.opt().nogoods_limit), d(0),
102 idle(false) {
103 tracer.worker();
104 if (s != nullptr) {
105 if (s->status(*this) == SS_FAILED) {
106 fail++;
107 cur = nullptr;
108 if (!engine().opt().clone)
109 delete s;
110 } else {
111 cur = snapshot(s,engine().opt());
112 }
113 } else {
114 cur = nullptr;
115 }
116 }
117
118 template<class Tracer>
119 forceinline
121 : _opt(o), _cmd(C_WAIT), solutions(heap) {
122 // Initialize termination information
125 // Initialize search information
126 n_busy = workers();
127 has_stopped.store(false, std::memory_order_release);
128 // Initialize reset information
130 }
131
132
133 /*
134 * Statistics
135 */
136 template<class Tracer>
137 forceinline Statistics
139 m.acquire();
140 Statistics s = *this;
141 m.release();
142 return s;
143 }
144
145
146 /*
147 * Engine: search control
148 */
149 template<class Tracer>
150 forceinline bool
152 return solutions.empty() && (n_busy > 0) &&
153 !has_stopped.load(std::memory_order_acquire);
154 }
155 template<class Tracer>
156 forceinline void
158 m_search.acquire();
159 bool bs = signal();
160 n_busy--;
161 if (bs && (n_busy == 0))
162 e_search.signal();
163 m_search.release();
164 }
165
166 template<class Tracer>
167 forceinline void
169 m_search.acquire();
170 assert(n_busy > 0);
171 n_busy++;
172 m_search.release();
173 }
174
175 template<class Tracer>
176 forceinline void
178 m_search.acquire();
179 bool bs = signal();
180 has_stopped.store(true, std::memory_order_release);
181 if (bs)
182 e_search.signal();
183 m_search.release();
184 }
185
186
187 /*
188 * Engine: termination control
189 */
190 template<class Tracer>
191 forceinline void
193 unsigned int n;
194 _m_term.acquire();
195 n = --_n_not_terminated;
196 _m_term.release();
197 // The signal must be outside of the look, otherwise a thread might be
198 // terminated that still holds a mutex.
199 if (n == 0)
200 _e_terminate.signal();
201 }
202
203 template<class Tracer>
204 forceinline void
206 _m_term.acquire();
207 if (--_n_term_not_ack == 0)
208 _e_term_ack.signal();
209 _m_term.release();
210 }
211
212 template<class Tracer>
213 forceinline void
215 _m_wait_terminate.acquire();
216 _m_wait_terminate.release();
217 }
218
219 template<class Tracer>
220 forceinline void
222 // Grab the wait mutex for termination
223 _m_wait_terminate.acquire();
224 // Release all threads
226 // Wait until all threads have acknowledged termination request
227 _e_term_ack.wait();
228 // Release waiting threads
229 _m_wait_terminate.release();
230 // Wait until all threads have in fact terminated
231 _e_terminate.wait();
232 // Now all threads are terminated!
233 }
234
235 /*
236 * Engine: reset control
237 */
238 template<class Tracer>
239 forceinline void
241 _m_reset.acquire();
242 if (--_n_reset_not_ack == 0)
243 e_reset_ack_start.signal();
244 _m_reset.release();
245 }
246
247 template<class Tracer>
248 forceinline void
250 _m_reset.acquire();
251 if (++_n_reset_not_ack == workers())
252 e_reset_ack_stop.signal();
253 _m_reset.release();
254 }
255
256 template<class Tracer>
257 forceinline void
259 m_wait_reset.acquire();
260 m_wait_reset.release();
261 }
262
263
264
265 /*
266 * Worker: finding and stealing working
267 */
268 template<class Tracer>
269 forceinline Space*
270 Engine<Tracer>::Worker::steal(unsigned long int& d,
271 Tracer& myt, Tracer& ot) {
272 /*
273 * Make a quick check whether the worker might have work
274 *
275 * If that is not true any longer, the worker will be asked
276 * again eventually.
277 */
278 m.acquire();
279 Space* s = path.steal() ? path.steal(*this,d,myt,ot) : nullptr;
280 m.release();
281 // Tell that there will be one more busy worker
282 if (s != nullptr)
283 engine().busy();
284 return s;
285 }
286
287 /*
288 * Return No-Goods
289 */
290 template<class Tracer>
291 forceinline NoGoods&
293 return path;
294 }
295
296 /*
297 * Engine: search control
298 */
299 template<class Tracer>
300 Space*
302 // Invariant: the worker holds the wait mutex
303 m_search.acquire();
304 if (!solutions.empty()) {
305 // No search needs to be done, take leftover solution
306 Space* s = solutions.pop();
307 m_search.release();
308 return s;
309 }
310 // We ignore stopped (it will be reported again if needed)
311 has_stopped.store(false, std::memory_order_release);
312 // No more solutions?
313 if (n_busy == 0) {
314 m_search.release();
315 return nullptr;
316 }
317 m_search.release();
318 // Okay, now search has to continue, make the guys work
320
321 /*
322 * Wait until a search related event has happened. It might be that
323 * the event has already been signalled in the last run, but the
324 * solution has been removed. So we have to try until there has
325 * something new happened.
326 */
327 while (true) {
328 e_search.wait();
329 m_search.acquire();
330 if (!solutions.empty()) {
331 // Report solution
332 Space* s = solutions.pop();
333 m_search.release();
334 // Make workers wait again
335 block();
336 return s;
337 }
338 // No more solutions or stopped?
339 if ((n_busy == 0) || has_stopped.load(std::memory_order_acquire)) {
340 m_search.release();
341 // Make workers wait again
342 block();
343 return nullptr;
344 }
345 m_search.release();
346 }
348 return nullptr;
349 }
350
351 template<class Tracer>
354 return &_engine;
355 }
356
357 /*
358 * Termination and deletion
359 */
360 template<class Tracer>
362 delete cur;
363 path.reset(0);
364 tracer.done();
365 }
366
367 /*
368 * Destructor
369 */
370 template<class Tracer>
372 while (!solutions.empty())
373 delete solutions.pop();
374 }
375
376}}}
377
378// STATISTICS: search-par
No-goods recorded from restarts.
Definition core.hpp:1599
Search engine options
Definition search.hh:751
double threads
Number of threads to use.
Definition search.hh:756
Support::Mutex m
Mutex for access to worker.
Definition engine.hh:62
Engine & _engine
Reference to engine.
Definition engine.hh:60
NoGoods & nogoods(void)
Return no-goods.
Definition engine.hpp:292
Statistics statistics(void)
Return statistics.
Definition engine.hpp:138
Space * cur
Current space being explored.
Definition engine.hh:66
virtual ~Worker(void)
Destructor.
Definition engine.hpp:361
Tracer tracer
Search tracer.
Definition engine.hh:57
Space * steal(unsigned long int &d, Tracer &myt, Tracer &ot)
Hand over some work (nullptr if no work available).
Definition engine.hpp:270
unsigned int d
Distance until next clone.
Definition engine.hh:68
bool idle
Whether the worker is idle.
Definition engine.hh:70
Path< Tracer > path
Current path ins search tree.
Definition engine.hh:64
virtual Support::Terminator * terminator(void) const
Terminator (engine).
Definition engine.hpp:353
Engine & engine(void) const
Provide access to engine.
Definition engine.hpp:46
Parallel depth-first search engine
Definition engine.hh:51
void idle(void)
Report that worker is idle.
Definition engine.hpp:157
void wait(void)
Ensure that worker waits.
Definition engine.hpp:89
Support::Event _e_terminate
Event for termination (all threads have terminated).
Definition engine.hh:134
void ack_reset_stop(void)
For worker to acknowledge stop of reset cycle.
Definition engine.hpp:249
const Options & opt(void) const
Provide access to search options.
Definition engine.hpp:51
Support::Mutex _m_wait_terminate
Mutex for waiting for termination.
Definition engine.hh:130
Support::Event e_reset_ack_stop
Event for reset acknowledgment stopped.
Definition engine.hh:156
Support::Mutex _m_wait
Mutex for forcing workers to wait.
Definition engine.hh:108
Support::Event e_search
Event for search (solution found, no more solutions, search stopped).
Definition engine.hh:174
virtual Space * next(void)
Return next solution (nullptr, if none exists or search has been stopped).
Definition engine.hpp:301
Support::Event _e_term_ack
Event for termination acknowledgment.
Definition engine.hh:128
Support::DynamicQueue< Space *, Heap > solutions
Queue of solutions.
Definition engine.hh:176
virtual bool stopped(void) const
Check whether engine has been stopped.
Definition engine.hpp:61
void stop(void)
Report that worker has been stopped.
Definition engine.hpp:177
void block(void)
Block all workers.
Definition engine.hpp:77
Support::Mutex m_wait_reset
Mutex for waiting for reset.
Definition engine.hh:158
Support::Mutex m_search
Mutex for search.
Definition engine.hh:172
Support::Event e_reset_ack_start
Event for reset acknowledgment started.
Definition engine.hh:154
Support::Mutex _m_term
Mutex for access to termination information.
Definition engine.hh:124
std::atomic< bool > has_stopped
Whether a worker had been stopped.
Definition engine.hh:180
Cmd cmd(void) const
Return current command.
Definition engine.hpp:72
virtual ~Engine(void)
Destructor.
Definition engine.hpp:371
Engine(const Options &o)
Initialize with options o.
Definition engine.hpp:120
Options _opt
Search options.
Definition engine.hh:88
void busy(void)
Report that worker is busy.
Definition engine.hpp:168
volatile unsigned int _n_reset_not_ack
Number of workers that have not yet acknowledged reset.
Definition engine.hh:152
void release(Cmd c)
Release all workers.
Definition engine.hpp:83
bool signal(void) const
Whether search state changed such that signal is needed.
Definition engine.hpp:151
void ack_reset_start(void)
For worker to acknowledge start of reset cycle.
Definition engine.hpp:240
volatile unsigned int _n_term_not_ack
Number of workers that have not yet acknowledged termination.
Definition engine.hh:126
void wait_reset(void)
For worker to wait for all workers to reset.
Definition engine.hpp:258
volatile unsigned int _n_not_terminated
Number of not yet terminated workers.
Definition engine.hh:132
virtual void terminated(void)
For worker to register termination.
Definition engine.hpp:192
void terminate(void)
For engine to perform thread termination.
Definition engine.hpp:221
std::atomic< Cmd > _cmd
The current command.
Definition engine.hh:106
Support::Mutex _m_reset
Mutex for access to reset information.
Definition engine.hh:150
volatile unsigned int n_busy
Number of busy workers.
Definition engine.hh:178
void wait_terminate(void)
For worker to wait until termination is legal.
Definition engine.hpp:214
unsigned int workers(void) const
Return number of workers.
Definition engine.hpp:56
Cmd
Commands from engine to workers.
Definition engine.hh:98
@ C_WORK
Perform work.
Definition engine.hh:99
@ C_WAIT
Run into wait lock.
Definition engine.hh:100
void ack_terminate(void)
For worker to acknowledge termination command.
Definition engine.hpp:205
Search engine statistics
Definition search.hh:151
Statistics(void)
Initialize.
unsigned long long int fail
Number of failed nodes in search tree.
Definition search.hh:154
Worker(void)
Initialize.
Definition worker.hh:70
Computation spaces.
Definition core.hpp:1775
An interface for objects that can be called after a thread has terminated (after running the thread's...
Definition thread.hpp:168
static void releaseGlobalMutex(Mutex *m)
release globally acquired mutex m
static void acquireGlobalMutex(Mutex *m)
acquire mutex m globally and possibly lock
Heap heap
The single global heap.
SpaceStatus status(StatusStatistics &stat)
Query space status.
@ SS_FAILED
Space is failed
Definition core.hpp:1715
Search engines
Space * snapshot(Space *s, const Options &o)
Clone space s depending on options o.
Definition support.hh:71
Gecode toplevel namespace
#define GECODE_NEVER
Assert that this command is never executed.
Definition macros.hpp:56