Subversion Repositories Games.Chess Giants

Rev

Rev 96 | Rev 169 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.   Stockfish, a UCI chess playing engine derived from Glaurung 2.1
  3.   Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
  4.   Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
  5.   Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
  6.  
  7.   Stockfish is free software: you can redistribute it and/or modify
  8.   it under the terms of the GNU General Public License as published by
  9.   the Free Software Foundation, either version 3 of the License, or
  10.   (at your option) any later version.
  11.  
  12.   Stockfish is distributed in the hope that it will be useful,
  13.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.   GNU General Public License for more details.
  16.  
  17.   You should have received a copy of the GNU General Public License
  18.   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19. */
  20.  
  21. #include <algorithm> // For std::count
  22. #include <cassert>
  23.  
  24. #include "movegen.h"
  25. #include "search.h"
  26. #include "thread.h"
  27. #include "uci.h"
  28. #include "syzygy/tbprobe.h"
  29.  
  30. ThreadPool Threads; // Global object
  31.  
  32. /// Thread constructor launches the thread and then waits until it goes to sleep
  33. /// in idle_loop().
  34.  
  35. Thread::Thread() {
  36.  
  37.   resetCalls = exit = false;
  38.   maxPly = callsCnt = 0;
  39.   tbHits = 0;
  40.   history.clear();
  41.   counterMoves.clear();
  42.   idx = Threads.size(); // Start from 0
  43.  
  44.   std::unique_lock<Mutex> lk(mutex);
  45.   searching = true;
  46.   nativeThread = std::thread(&Thread::idle_loop, this);
  47.   sleepCondition.wait(lk, [&]{ return !searching; });
  48. }
  49.  
  50.  
  51. /// Thread destructor waits for thread termination before returning
  52.  
  53. Thread::~Thread() {
  54.  
  55.   mutex.lock();
  56.   exit = true;
  57.   sleepCondition.notify_one();
  58.   mutex.unlock();
  59.   nativeThread.join();
  60. }
  61.  
  62.  
  63. /// Thread::wait_for_search_finished() waits on sleep condition
  64. /// until not searching
  65.  
  66. void Thread::wait_for_search_finished() {
  67.  
  68.   std::unique_lock<Mutex> lk(mutex);
  69.   sleepCondition.wait(lk, [&]{ return !searching; });
  70. }
  71.  
  72.  
  73. /// Thread::wait() waits on sleep condition until condition is true
  74.  
  75. void Thread::wait(std::atomic_bool& condition) {
  76.  
  77.   std::unique_lock<Mutex> lk(mutex);
  78.   sleepCondition.wait(lk, [&]{ return bool(condition); });
  79. }
  80.  
  81.  
  82. /// Thread::start_searching() wakes up the thread that will start the search
  83.  
  84. void Thread::start_searching(bool resume) {
  85.  
  86.   std::unique_lock<Mutex> lk(mutex);
  87.  
  88.   if (!resume)
  89.       searching = true;
  90.  
  91.   sleepCondition.notify_one();
  92. }
  93.  
  94.  
  95. /// Thread::idle_loop() is where the thread is parked when it has no work to do
  96.  
  97. void Thread::idle_loop() {
  98.  
  99.   while (!exit)
  100.   {
  101.       std::unique_lock<Mutex> lk(mutex);
  102.  
  103.       searching = false;
  104.  
  105.       while (!searching && !exit)
  106.       {
  107.           sleepCondition.notify_one(); // Wake up any waiting thread
  108.           sleepCondition.wait(lk);
  109.       }
  110.  
  111.       lk.unlock();
  112.  
  113.       if (!exit)
  114.           search();
  115.   }
  116. }
  117.  
  118.  
  119. /// ThreadPool::init() creates and launches requested threads that will go
  120. /// immediately to sleep. We cannot use a constructor because Threads is a
  121. /// static object and we need a fully initialized engine at this point due to
  122. /// allocation of Endgames in the Thread constructor.
  123.  
  124. void ThreadPool::init() {
  125.  
  126.   push_back(new MainThread);
  127.   read_uci_options();
  128. }
  129.  
  130.  
  131. /// ThreadPool::exit() terminates threads before the program exits. Cannot be
  132. /// done in destructor because threads must be terminated before deleting any
  133. /// static objects while still in main().
  134.  
  135. void ThreadPool::exit() {
  136.  
  137.   while (size())
  138.       delete back(), pop_back();
  139. }
  140.  
  141.  
  142. /// ThreadPool::read_uci_options() updates internal threads parameters from the
  143. /// corresponding UCI options and creates/destroys threads to match requested
  144. /// number. Thread objects are dynamically allocated.
  145.  
  146. void ThreadPool::read_uci_options() {
  147.  
  148.   size_t requested = Options["Threads"];
  149.  
  150.   assert(requested > 0);
  151.  
  152.   while (size() < requested)
  153.       push_back(new Thread);
  154.  
  155.   while (size() > requested)
  156.       delete back(), pop_back();
  157. }
  158.  
  159.  
  160. /// ThreadPool::nodes_searched() returns the number of nodes searched
  161.  
  162. uint64_t ThreadPool::nodes_searched() const {
  163.  
  164.   uint64_t nodes = 0;
  165.   for (Thread* th : *this)
  166.       nodes += th->rootPos.nodes_searched();
  167.   return nodes;
  168. }
  169.  
  170.  
  171. /// ThreadPool::tb_hits() returns the number of TB hits
  172.  
  173. uint64_t ThreadPool::tb_hits() const {
  174.  
  175.   uint64_t hits = 0;
  176.   for (Thread* th : *this)
  177.       hits += th->tbHits;
  178.   return hits;
  179. }
  180.  
  181.  
  182. /// ThreadPool::start_thinking() wakes up the main thread sleeping in idle_loop()
  183. /// and starts a new search, then returns immediately.
  184.  
  185. void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
  186.                                 const Search::LimitsType& limits) {
  187.  
  188.   main()->wait_for_search_finished();
  189.  
  190.   Search::Signals.stopOnPonderhit = Search::Signals.stop = false;
  191.   Search::Limits = limits;
  192.   Search::RootMoves rootMoves;
  193.  
  194.   for (const auto& m : MoveList<LEGAL>(pos))
  195.       if (   limits.searchmoves.empty()
  196.           || std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m))
  197.           rootMoves.push_back(Search::RootMove(m));
  198.  
  199.   if (!rootMoves.empty())
  200.       Tablebases::filter_root_moves(pos, rootMoves);
  201.  
  202.   // After ownership transfer 'states' becomes empty, so if we stop the search
  203.   // and call 'go' again without setting a new position states.get() == NULL.
  204.   assert(states.get() || setupStates.get());
  205.  
  206.   if (states.get())
  207.       setupStates = std::move(states); // Ownership transfer, states is now empty
  208.  
  209.   StateInfo tmp = setupStates->back();
  210.  
  211.   for (Thread* th : Threads)
  212.   {
  213.       th->maxPly = 0;
  214.       th->tbHits = 0;
  215.       th->rootDepth = DEPTH_ZERO;
  216.       th->rootMoves = rootMoves;
  217.       th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th);
  218.   }
  219.  
  220.   setupStates->back() = tmp; // Restore st->previous, cleared by Position::set()
  221.  
  222.   main()->start_searching();
  223. }
  224.