engine.hh
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #ifndef __GECODE_SEARCH_PARALLEL_ENGINE_HH__
00039 #define __GECODE_SEARCH_PARALLEL_ENGINE_HH__
00040
00041 #include <gecode/search.hh>
00042 #include <gecode/search/support.hh>
00043 #include <gecode/search/worker.hh>
00044 #include <gecode/search/parallel/path.hh>
00045
00046 #include <gecode/support/thread.hh>
00047
00048 namespace Gecode { namespace Search { namespace Parallel {
00049
00051 class Engine : public Search::Engine {
00052 protected:
00054 class Worker : public Search::Worker, public Support::Runnable {
00055 protected:
00057 Engine& _engine;
00059 Support::Mutex m;
00061 Path path;
00063 Space* cur;
00065 unsigned int d;
00067 bool idle;
00068 public:
00070 Worker(Space* s, size_t sz, Engine& e);
00072 Space* steal(unsigned long int& d);
00074 Statistics statistics(void);
00076 Engine& engine(void) const;
00078 virtual ~Worker(void);
00079 };
00081 const Options _opt;
00082 public:
00084 const Options& opt(void) const;
00086 unsigned int workers(void) const;
00087
00089
00090
00091 enum Cmd {
00092 C_WORK,
00093 C_WAIT,
00094 C_RESET,
00095 C_TERMINATE
00096 };
00097 protected:
00099 volatile Cmd _cmd;
00101 Support::Mutex _m_wait;
00102 public:
00104 Cmd cmd(void) const;
00106 void block(void);
00108 void release(Cmd c);
00110 void wait(void);
00112
00114
00115 protected:
00117 Support::Mutex _m_term;
00119 volatile unsigned int _n_term_not_ack;
00121 Support::Event _e_term_ack;
00123 Support::Mutex _m_wait_terminate;
00125 volatile unsigned int _n_not_terminated;
00127 Support::Event _e_terminate;
00128 public:
00130 void ack_terminate(void);
00132 void terminated(void);
00134 void wait_terminate(void);
00136 void terminate(void);
00138
00140
00141 protected:
00143 Support::Mutex _m_reset;
00145 volatile unsigned int _n_reset_not_ack;
00147 Support::Event e_reset_ack_start;
00149 Support::Event e_reset_ack_stop;
00151 Support::Mutex m_wait_reset;
00152 public:
00154 void ack_reset_start(void);
00156 void ack_reset_stop(void);
00158 void wait_reset(void);
00160
00162
00163 protected:
00165 Support::Mutex m_search;
00167 Support::Event e_search;
00169 Support::DynamicQueue<Space*,Heap> solutions;
00171 volatile unsigned int n_busy;
00173 volatile bool has_stopped;
00175 bool signal(void) const;
00176 public:
00178 void idle(void);
00180 void busy(void);
00182 void stop(void);
00184
00186
00187
00188 Engine(const Options& o);
00190 virtual Space* next(void);
00192 virtual bool stopped(void) const;
00194 };
00195
00196
00197
00198
00199
00200 forceinline Engine&
00201 Engine::Worker::engine(void) const {
00202 return _engine;
00203 }
00204 forceinline const Options&
00205 Engine::opt(void) const {
00206 return _opt;
00207 }
00208 forceinline unsigned int
00209 Engine::workers(void) const {
00210 return opt().threads;
00211 }
00212
00213
00214
00215
00216
00217 forceinline Engine::Cmd
00218 Engine::cmd(void) const {
00219 return _cmd;
00220 }
00221 forceinline void
00222 Engine::block(void) {
00223 _cmd = C_WAIT;
00224 _m_wait.acquire();
00225 }
00226 forceinline void
00227 Engine::release(Cmd c) {
00228 _cmd = c;
00229 _m_wait.release();
00230 }
00231 forceinline void
00232 Engine::wait(void) {
00233 _m_wait.acquire(); _m_wait.release();
00234 }
00235
00236
00237
00238
00239
00240 forceinline
00241 Engine::Worker::Worker(Space* s, size_t sz, Engine& e)
00242 : Search::Worker(sz), _engine(e), d(0), idle(false) {
00243 if (s != NULL) {
00244 cur = (s->status(*this) == SS_FAILED) ?
00245 NULL : snapshot(s,engine().opt());
00246 if (cur == NULL)
00247 fail++;
00248 } else {
00249 cur = NULL;
00250 }
00251 current(s);
00252 current(NULL);
00253 current(cur);
00254 }
00255
00256 forceinline
00257 Engine::Engine(const Options& o)
00258 : _opt(o), solutions(heap) {
00259
00260 _n_term_not_ack = workers();
00261 _n_not_terminated = workers();
00262
00263 n_busy = workers();
00264 has_stopped = false;
00265
00266 _n_reset_not_ack = workers();
00267 }
00268
00269
00270
00271
00272
00273 forceinline Statistics
00274 Engine::Worker::statistics(void) {
00275 m.acquire();
00276 Statistics s = *this;
00277 s.memory += path.size();
00278 m.release();
00279 return s;
00280 }
00281
00282
00283
00284
00285
00286 forceinline bool
00287 Engine::signal(void) const {
00288 return solutions.empty() && (n_busy > 0) && !has_stopped;
00289 }
00290 forceinline void
00291 Engine::idle(void) {
00292 m_search.acquire();
00293 bool bs = signal();
00294 n_busy--;
00295 if (bs && (n_busy == 0))
00296 e_search.signal();
00297 m_search.release();
00298 }
00299 forceinline void
00300 Engine::busy(void) {
00301 m_search.acquire();
00302 assert(n_busy > 0);
00303 n_busy++;
00304 m_search.release();
00305 }
00306 forceinline void
00307 Engine::stop(void) {
00308 m_search.acquire();
00309 bool bs = signal();
00310 has_stopped = true;
00311 if (bs)
00312 e_search.signal();
00313 m_search.release();
00314 }
00315
00316
00317
00318
00319
00320 forceinline void
00321 Engine::terminated(void) {
00322 unsigned int n;
00323 _m_term.acquire();
00324 n = --_n_not_terminated;
00325 _m_term.release();
00326
00327
00328 if (n == 0)
00329 _e_terminate.signal();
00330 }
00331
00332 forceinline void
00333 Engine::ack_terminate(void) {
00334 _m_term.acquire();
00335 if (--_n_term_not_ack == 0)
00336 _e_term_ack.signal();
00337 _m_term.release();
00338 }
00339
00340 forceinline void
00341 Engine::wait_terminate(void) {
00342 _m_wait_terminate.acquire();
00343 _m_wait_terminate.release();
00344 }
00345
00346 forceinline void
00347 Engine::terminate(void) {
00348
00349 _m_wait_terminate.acquire();
00350
00351 release(C_TERMINATE);
00352
00353 _e_term_ack.wait();
00354
00355 _m_wait_terminate.release();
00356
00357 _e_terminate.wait();
00358
00359 }
00360
00361
00362
00363
00364
00365
00366 forceinline void
00367 Engine::ack_reset_start(void) {
00368 _m_reset.acquire();
00369 if (--_n_reset_not_ack == 0)
00370 e_reset_ack_start.signal();
00371 _m_reset.release();
00372 }
00373
00374 forceinline void
00375 Engine::ack_reset_stop(void) {
00376 _m_reset.acquire();
00377 if (++_n_reset_not_ack == workers())
00378 e_reset_ack_stop.signal();
00379 _m_reset.release();
00380 }
00381
00382 forceinline void
00383 Engine::wait_reset(void) {
00384 m_wait_reset.acquire();
00385 m_wait_reset.release();
00386 }
00387
00388
00389
00390
00391
00392
00393 forceinline Space*
00394 Engine::Worker::steal(unsigned long int& d) {
00395
00396
00397
00398
00399
00400
00401 if (!path.steal())
00402 return NULL;
00403 m.acquire();
00404 Space* s = path.steal(*this,d);
00405 m.release();
00406
00407 if (s != NULL)
00408 engine().busy();
00409 return s;
00410 }
00411
00412 }}}
00413
00414 #endif
00415
00416