Rework Thread hierarchy
authorMarco Costalba <mcostalba@gmail.com>
Wed, 31 Jul 2013 07:33:26 +0000 (09:33 +0200)
committerMarco Costalba <mcostalba@gmail.com>
Wed, 31 Jul 2013 16:35:52 +0000 (18:35 +0200)
Introduce ThreadBase struct that is search
agnostic and just handles low level stuff,
and derive all the other specialized classes
form here.

In particular TimerThread does not hinerits
anymore all the search related stuff from Thread.

Also some renaming while there.

Suggested by Steven Edwards

No functional change.

src/benchmark.cpp
src/search.cpp
src/thread.cpp
src/thread.h
src/uci.cpp

index 25dab6cc7d7bd8b026b57633e6b31364b76bbb9b..f22ea6dada5d2ca7246039d45454c9e5e7e01a63 100644 (file)
@@ -118,7 +118,7 @@ void benchmark(const Position& current, istream& is) {
 
   for (size_t i = 0; i < fens.size(); i++)
   {
-      Position pos(fens[i], Options["UCI_Chess960"], Threads.main_thread());
+      Position pos(fens[i], Options["UCI_Chess960"], Threads.main());
 
       cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl;
 
index 78a72beccfdc777e549a7dd786d8483208089b9f..dfe18bc88599f75e8340fbf5163958681b88a16b 100644 (file)
@@ -809,7 +809,7 @@ moves_loop: // When in check and at SpNode search starts from here
       {
           Signals.firstRootMove = (moveCount == 1);
 
-          if (thisThread == Threads.main_thread() && Time::now() - SearchTime > 3000)
+          if (thisThread == Threads.main() && Time::now() - SearchTime > 3000)
               sync_cout << "info depth " << depth / ONE_PLY
                         << " currmove " << move_to_uci(move, pos.is_chess960())
                         << " currmovenumber " << moveCount + PVIdx << sync_endl;
index 25ef1853c03755762db7645771ffdccfb599ff26..1772a41931017c2ed1857288ba6a90955deb4b75 100644 (file)
@@ -34,7 +34,7 @@ namespace {
  // start_routine() is the C function which is called when a new thread
  // is launched. It is a wrapper to the virtual function idle_loop().
 
- extern "C" { long start_routine(Thread* th) { th->idle_loop(); return 0; } }
+ extern "C" { long start_routine(ThreadBase* th) { th->idle_loop(); return 0; } }
 
 
  // Helpers to launch a thread after creation and joining before delete. Must be
@@ -43,11 +43,11 @@ namespace {
 
  template<typename T> T* new_thread() {
    T* th = new T();
-   thread_create(th->handle, start_routine, th);
+   thread_create(th->handle, start_routine, th); // Will go to sleep
    return th;
  }
 
- void delete_thread(Thread* th) {
+ void delete_thread(ThreadBase* th) {
    th->exit = true; // Search must be already finished
    th->notify_one();
    thread_join(th->handle); // Wait for thread termination
@@ -57,12 +57,32 @@ namespace {
 }
 
 
-// Thread c'tor starts a newly-created thread of execution that will call
-// the the virtual function idle_loop(), going immediately to sleep.
+// ThreadBase::notify_one() wakes up the thread when there is some work to do
+
+void ThreadBase::notify_one() {
+
+  mutex.lock();
+  sleepCondition.notify_one();
+  mutex.unlock();
+}
+
+
+// ThreadBase::wait_for() set the thread to sleep until condition 'b' turns true
+
+void ThreadBase::wait_for(volatile const bool& b) {
+
+  mutex.lock();
+  while (!b) sleepCondition.wait(mutex);
+  mutex.unlock();
+}
+
+
+// Thread c'tor just inits data but does not launch any thread of execution that
+// instead will be started only upon c'tor returns.
 
 Thread::Thread() /* : splitPoints() */ { // Value-initialization bug in MSVC
 
-  searching = exit = false;
+  searching = false;
   maxPly = splitPointsSize = 0;
   activeSplitPoint = NULL;
   activePosition = NULL;
@@ -124,26 +144,6 @@ void MainThread::idle_loop() {
 }
 
 
-// Thread::notify_one() wakes up the thread when there is some search to do
-
-void Thread::notify_one() {
-
-  mutex.lock();
-  sleepCondition.notify_one();
-  mutex.unlock();
-}
-
-
-// Thread::wait_for() set the thread to sleep until condition 'b' turns true
-
-void Thread::wait_for(volatile const bool& b) {
-
-  mutex.lock();
-  while (!b) sleepCondition.wait(mutex);
-  mutex.unlock();
-}
-
-
 // Thread::cutoff_occurred() checks whether a beta cutoff has occurred in the
 // current active split point, or in some ancestor of the split point.
 
@@ -349,7 +349,7 @@ template void Thread::split< true>(Position&, Stack*, Value, Value, Value*, Move
 
 void ThreadPool::wait_for_think_finished() {
 
-  MainThread* t = main_thread();
+  MainThread* t = main();
   t->mutex.lock();
   while (t->thinking) sleepCondition.wait(t->mutex);
   t->mutex.unlock();
@@ -382,6 +382,6 @@ void ThreadPool::start_thinking(const Position& pos, const LimitsType& limits,
           || std::count(searchMoves.begin(), searchMoves.end(), *it))
           RootMoves.push_back(RootMove(*it));
 
-  main_thread()->thinking = true;
-  main_thread()->notify_one(); // Starts main thread
+  main()->thinking = true;
+  main()->notify_one(); // Starts main thread
 }
index f5135804710b4003c06cbffaef24c73119d294af..7557c0e7a90a80695dc37ae10aae4d2d8b08867a 100644 (file)
@@ -86,21 +86,35 @@ struct SplitPoint {
 };
 
 
+/// ThreadBase struct is the base of the hierarchy from where we derive all the
+/// specialized thread classes.
+
+struct ThreadBase {
+
+  ThreadBase() : exit(false) {}
+  virtual ~ThreadBase() {}
+  virtual void idle_loop() = 0;
+  void notify_one();
+  void wait_for(volatile const bool& b);
+
+  Mutex mutex;
+  ConditionVariable sleepCondition;
+  NativeHandle handle;
+  volatile bool exit;
+};
+
+
 /// Thread struct keeps together all the thread related stuff like locks, state
 /// and especially split points. We also use per-thread pawn and material hash
 /// tables so that once we get a pointer to an entry its life time is unlimited
 /// and we don't have to care about someone changing the entry under our feet.
 
-struct Thread {
+struct Thread : public ThreadBase {
 
   Thread();
-  virtual ~Thread() {}
-
   virtual void idle_loop();
-  void notify_one();
   bool cutoff_occurred() const;
   bool is_available_to(Thread* master) const;
-  void wait_for(volatile const bool& b);
 
   template <bool Fake>
   void split(Position& pos, Search::Stack* ss, Value alpha, Value beta, Value* bestValue, Move* bestMove,
@@ -113,17 +127,13 @@ struct Thread {
   Position* activePosition;
   size_t idx;
   int maxPly;
-  Mutex mutex;
-  ConditionVariable sleepCondition;
-  NativeHandle handle;
   SplitPoint* volatile activeSplitPoint;
   volatile int splitPointsSize;
   volatile bool searching;
-  volatile bool exit;
 };
 
 
-/// MainThread and TimerThread are sublassed from Thread to characterize the two
+/// MainThread and TimerThread are derived classes used to characterize the two
 /// special threads: the main one and the recurring timer.
 
 struct MainThread : public Thread {
@@ -132,7 +142,7 @@ struct MainThread : public Thread {
   volatile bool thinking;
 };
 
-struct TimerThread : public Thread {
+struct TimerThread : public ThreadBase {
   TimerThread() : msec(0) {}
   virtual void idle_loop();
   int msec;
@@ -148,7 +158,7 @@ struct ThreadPool : public std::vector<Thread*> {
   void init(); // No c'tor and d'tor, threads rely on globals that should
   void exit(); // be initialized and valid during the whole thread lifetime.
 
-  MainThread* main_thread() { return static_cast<MainThread*>((*this)[0]); }
+  MainThread* main() { return static_cast<MainThread*>((*this)[0]); }
   void read_uci_options();
   Thread* available_slave(Thread* master) const;
   void wait_for_think_finished();
index 3bd3c1a531c91db0b7e3668728915defdd48c606..95d050f3bcaa66b624f159bc144ebfd4cf974f18 100644 (file)
@@ -56,7 +56,7 @@ namespace {
 
 void UCI::loop(const string& args) {
 
-  Position pos(StartFEN, false, Threads.main_thread()); // The root position
+  Position pos(StartFEN, false, Threads.main()); // The root position
   string token, cmd = args;
 
   do {
@@ -77,7 +77,7 @@ void UCI::loop(const string& args) {
           if (token != "ponderhit" || Search::Signals.stopOnPonderhit)
           {
               Search::Signals.stop = true;
-              Threads.main_thread()->notify_one(); // Could be sleeping
+              Threads.main()->notify_one(); // Could be sleeping
           }
           else
               Search::Limits.ponder = false;
@@ -146,7 +146,7 @@ namespace {
     else
         return;
 
-    pos.set(fen, Options["UCI_Chess960"], Threads.main_thread());
+    pos.set(fen, Options["UCI_Chess960"], Threads.main());
     SetupStates = Search::StateStackPtr(new std::stack<StateInfo>());
 
     // Parse move list (if any)