]> git.sesse.net Git - stockfish/blob - src/thread.cpp
History Pruning: Don't prune the main killer move.
[stockfish] / src / thread.cpp
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
6   Stockfish is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   Stockfish is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <algorithm> // For std::count
21 #include <cassert>
22
23 #include "movegen.h"
24 #include "search.h"
25 #include "thread.h"
26 #include "uci.h"
27
28 using namespace Search;
29
30 ThreadPool Threads; // Global object
31
32 // Thread constructor makes some init and launches the thread that will go to
33 // sleep in idle_loop().
34
35 Thread::Thread() {
36
37   searching = true; // Avoid a race with start_thinking()
38   exit = resetCalls = false;
39   maxPly = callsCnt = 0;
40   history.clear();
41   counterMoves.clear();
42   idx = Threads.size(); // Starts from 0
43   std::thread::operator=(std::thread(&Thread::idle_loop, this));
44 }
45
46
47 // Thread destructor waits for thread termination before deleting
48
49 Thread::~Thread() {
50
51   mutex.lock();
52   exit = true; // Search must be already finished
53   mutex.unlock();
54
55   notify_one();
56   std::thread::join(); // Wait for thread termination
57 }
58
59
60 // Thread::join() waits for the thread to finish searching
61 void Thread::join() {
62
63   std::unique_lock<Mutex> lk(mutex);
64   sleepCondition.wait(lk, [&]{ return !searching; });
65 }
66
67
68 // Thread::notify_one() wakes up the thread when there is some work to do
69
70 void Thread::notify_one() {
71
72   std::unique_lock<Mutex> lk(mutex);
73   sleepCondition.notify_one();
74 }
75
76
77 // Thread::wait() set the thread to sleep until 'condition' turns true
78
79 void Thread::wait(std::atomic_bool& condition) {
80
81   std::unique_lock<Mutex> lk(mutex);
82   sleepCondition.wait(lk, [&]{ return bool(condition); });
83 }
84
85
86 // Thread::idle_loop() is where the thread is parked when it has no work to do
87
88 void Thread::idle_loop() {
89
90   while (!exit)
91   {
92       std::unique_lock<Mutex> lk(mutex);
93
94       searching = false;
95
96       while (!searching && !exit)
97       {
98           sleepCondition.notify_one(); // Wake up main thread if needed
99           sleepCondition.wait(lk);
100       }
101
102       lk.unlock();
103
104       if (!exit && searching)
105           search();
106   }
107 }
108
109
110 // ThreadPool::init() is called at startup to create and launch requested threads,
111 // that will go immediately to sleep. We cannot use a constructor because Threads
112 // is a static object and we need a fully initialized engine at this point due to
113 // allocation of Endgames in the Thread constructor.
114
115 void ThreadPool::init() {
116
117   push_back(new MainThread);
118   read_uci_options();
119 }
120
121
122 // ThreadPool::exit() terminates the threads before the program exits. Cannot be
123 // done in destructor because threads must be terminated before freeing us.
124
125 void ThreadPool::exit() {
126
127   for (Thread* th : *this)
128       delete th;
129
130   clear(); // Get rid of stale pointers
131 }
132
133
134 // ThreadPool::read_uci_options() updates internal threads parameters from the
135 // corresponding UCI options and creates/destroys threads to match the requested
136 // number. Thread objects are dynamically allocated to avoid creating all possible
137 // threads in advance (which include pawns and material tables), even if only a
138 // few are to be used.
139
140 void ThreadPool::read_uci_options() {
141
142   size_t requested  = Options["Threads"];
143
144   assert(requested > 0);
145
146   while (size() < requested)
147       push_back(new Thread);
148
149   while (size() > requested)
150   {
151       delete back();
152       pop_back();
153   }
154 }
155
156
157 // ThreadPool::nodes_searched() returns the number of nodes searched
158
159 int64_t ThreadPool::nodes_searched() {
160
161   int64_t nodes = 0;
162   for (Thread *th : *this)
163       nodes += th->rootPos.nodes_searched();
164   return nodes;
165 }
166
167
168 // ThreadPool::start_thinking() wakes up the main thread sleeping in
169 // MainThread::idle_loop() and starts a new search, then returns immediately.
170
171 void ThreadPool::start_thinking(const Position& pos, const LimitsType& limits,
172                                 StateStackPtr& states) {
173   for (Thread* th : Threads)
174       th->join();
175
176   Signals.stopOnPonderhit = Signals.firstRootMove = false;
177   Signals.stop = Signals.failedLowAtRoot = false;
178
179   main()->rootMoves.clear();
180   main()->rootPos = pos;
181   Limits = limits;
182   if (states.get()) // If we don't set a new position, preserve current state
183   {
184       SetupStates = std::move(states); // Ownership transfer here
185       assert(!states.get());
186   }
187
188   for (const auto& m : MoveList<LEGAL>(pos))
189       if (   limits.searchmoves.empty()
190           || std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m))
191           main()->rootMoves.push_back(RootMove(m));
192
193   main()->searching = true;
194   main()->notify_one(); // Wake up main thread: 'searching' must be already set
195 }