SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
ThreadPool.cpp
Go to the documentation of this file.
1 /**
2  * @file ThreadPool.cpp
3  *
4  * @author Gereon Kremer
5  * @since 2016-03-18
6  */
7 
8 #include "ThreadPool.h"
9 #include <smtrat-solver/Module.h>
10 
11 namespace smtrat
12 {
13  bool Task::operator<(const Task& rhs) const {
14  return mModule->threadPriority() < rhs.mModule->threadPriority();
15  }
16 
17  void ThreadPool::runTask(Task* task) {
18  mCounter++;
19  while (true) {
20  std::size_t index = task->conditionalIndex();
21  bool skipTask = shallBeSkipped(index);
22  if (!skipTask) {
23  SMTRAT_LOG_DEBUG("smtrat.parallel", "Executing " << task->getModule()->moduleName());
24  task->run();
25  SMTRAT_LOG_DEBUG("smtrat.parallel", "done.");
26  deleteTask(task);
27  if (notify(index)) {
28  mCounter--;
29  return;
30  }
31  } else {
32  deleteTask(task);
33  }
34  std::lock_guard<std::mutex> lock(mQueueMutex);
35  if (mQueue.empty()) {
36  mCounter--;
37  return;
38  }
39  task = mQueue.top();
40  mQueue.pop();
41  }
42  }
43 
45  SMTRAT_LOG_DEBUG("smtrat.parallel", "Submitting " << task->getModule()->moduleName());
46  /*auto tmpCounter =*/ mCounter.load();
47  //if (tmpCounter < mMaxThreads) { // TODO: Counter does currently not work correctly
48  std::thread(&ThreadPool::runTask, this, task).detach();
49  /*} else {
50  std::lock_guard<std::mutex> lock(mQueueMutex);
51  mQueue.push(task);
52  }*/
53  }
54 
55  Answer ThreadPool::runBackends(const std::vector<Module*>& _modules, bool _final, bool _full, carl::Variable _objective) {
56  if( _modules.empty() )
57  {
58  SMTRAT_LOG_DEBUG("smtrat.parallel", "Returning " << UNKNOWN);
59  return UNKNOWN;
60  }
61  assert(mCounter > 0);
62  std::size_t index = 0;
63  {
64  std::lock_guard<std::mutex> bsLock(mBackendSynchrosMutex);
65  index = mBackendSynchros.size();
67  }
68  std::vector<std::future<Answer>> futures;
69  for (const auto& m: _modules) {
70  SMTRAT_LOG_DEBUG("smtrat.parallel", "\tCreating task for " << m->moduleName());
71  Task* task = new Task(std::bind(&Module::check, m, _final, _full, _objective), m, index);
73  futures.emplace_back(task->getFuture());
74  submitBackend(task);
75  }
76  // wait until one task (backend check) fires the condition variable which means it has finished its check
78  {
79  std::lock_guard<std::mutex> bsLock(mBackendSynchrosMutex);
80  bs = mBackendSynchros[index];
81  }
82  mCounter--;
83  bs->wait();
84  {
85  std::lock_guard<std::mutex> bsLock(mBackendSynchrosMutex);
86  delete mBackendSynchros[index];
87  mBackendSynchros[index] = nullptr;
88  while (!mBackendSynchros.empty() && mBackendSynchros.back() == nullptr) {
89  mBackendSynchros.pop_back();
90  }
91  }
92  mCounter++;
93  Answer res = Answer::ABORTED;
94  for (auto& f: futures) {
95  Answer ans = Answer::ABORTED;
96  try
97  {
98  ans = f.get();
99  }
100  catch(const std::exception& e)
101  {
102  // If backend A returned before backend B
103  // TODO: This might also happen, if A return Unknown .. see for notify(..)
104  }
105  switch (ans) {
106  case Answer::ABORTED: break;
107  case Answer::UNKNOWN:
108  {
109  if( res == Answer::ABORTED )
110  res = Answer::UNKNOWN;
111  break;
112  }
113  case Answer::OPTIMAL:
114  case Answer::SAT:
115  {
116  assert( res != Answer::UNSAT );
117  res = ans;
118  break;
119  }
120  case Answer::UNSAT:
121  {
122  assert( res != Answer::SAT );
123  res = Answer::UNSAT;
124  break;
125  }
126  }
127  }
128  SMTRAT_LOG_DEBUG("smtrat.parallel", "Returning " << res);
129  return res;
130  }
131 } // namespace smtrat
thread_priority threadPriority() const
Definition: Module.h:414
virtual std::string moduleName() const
Definition: Module.h:615
virtual Answer check(bool _final=false, bool _full=true, carl::Variable _objective=carl::Variable::NO_VARIABLE)
Checks the received formula for consistency.
Definition: Module.cpp:86
bool operator<(const Task &rhs) const
Definition: ThreadPool.cpp:13
void run()
Definition: ThreadPool.h:35
std::future< Answer > getFuture()
Definition: ThreadPool.h:47
const Module * getModule() const
Definition: ThreadPool.h:39
const Module * mModule
Definition: ThreadPool.h:29
std::size_t conditionalIndex() const
Definition: ThreadPool.h:43
std::mutex mQueueMutex
Definition: ThreadPool.h:85
std::vector< BackendSynchronisation * > mBackendSynchros
Definition: ThreadPool.h:83
void submitBackend(Task *task)
Definition: ThreadPool.cpp:44
bool notify(std::size_t index)
Definition: ThreadPool.h:95
std::atomic< std::size_t > mNumberThreads
Initialized with 1: There is always the main thread in the beginning.
Definition: ThreadPool.h:79
Answer runBackends(const std::vector< Module * > &_modules, bool _final, bool _full, carl::Variable _objective)
Definition: ThreadPool.cpp:55
std::atomic< std::size_t > mCounter
Initialized with 1: There is always the main thread in the beginning.
Definition: ThreadPool.h:77
void runTask(Task *task)
Definition: ThreadPool.cpp:17
std::priority_queue< Task * > mQueue
Definition: ThreadPool.h:89
std::mutex mBackendSynchrosMutex
Definition: ThreadPool.h:81
void deleteTask(Task *task)
Definition: ThreadPool.h:109
bool shallBeSkipped(std::size_t index)
Definition: ThreadPool.h:91
Class to create the formulas for axioms.
Answer
An enum with the possible answers a Module can give.
Definition: types.h:57
@ OPTIMAL
Definition: types.h:57
@ UNKNOWN
Definition: types.h:57
@ ABORTED
Definition: types.h:57
#define SMTRAT_LOG_DEBUG(channel, msg)
Definition: logging.h:35