summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
ce84ab6)
Now that we don't have anymore TimerThread, there is
no need of this long class hierarchy.
Also assorted reformatting while there.
To verify no regression, passed at STC with 7 threads:
LLR: 2.97 (-2.94,2.94) [-5.00,0.00]
Total: 30990 W: 4945 L: 4942 D: 21103
No functional change.
template uint64_t Search::perft<true>(Position&, Depth);
template uint64_t Search::perft<true>(Position&, Depth);
-/// MainThread::think() is called by the main thread when the program receives
+/// MainThread::search() is called by the main thread when the program receives
/// the UCI 'go' command. It searches from root position and at the end prints
/// the "bestmove" to output.
/// the UCI 'go' command. It searches from root position and at the end prints
/// the "bestmove" to output.
-void MainThread::think() {
+void MainThread::search() {
Color us = rootPos.side_to_move();
Time.init(Limits, us, rootPos.game_ply());
Color us = rootPos.side_to_move();
Time.init(Limits, us, rootPos.game_ply());
- search(true); // Let's start searching!
+ Thread::search(); // Let's start searching!
}
// When playing in 'nodes as time' mode, subtract the searched nodes from
}
// When playing in 'nodes as time' mode, subtract the searched nodes from
// Wait until all threads have finished
for (Thread* th : Threads)
if (th != this)
// Wait until all threads have finished
for (Thread* th : Threads)
if (th != this)
- th->wait_while(th->searching);
// Check if there are threads with a better score than main thread.
Thread* bestThread = this;
// Check if there are threads with a better score than main thread.
Thread* bestThread = this;
// repeatedly with increasing depth until the allocated thinking time has been
// consumed, user stops the search, or the maximum search depth is reached.
// repeatedly with increasing depth until the allocated thinking time has been
// consumed, user stops the search, or the maximum search depth is reached.
-void Thread::search(bool isMainThread) {
Stack stack[MAX_PLY+4], *ss = stack+2; // To allow referencing (ss-2) and (ss+2)
Value bestValue, alpha, beta, delta;
Move easyMove = MOVE_NONE;
Stack stack[MAX_PLY+4], *ss = stack+2; // To allow referencing (ss-2) and (ss+2)
Value bestValue, alpha, beta, delta;
Move easyMove = MOVE_NONE;
+ bool isMainThread = (this == Threads.main());
std::memset(ss-2, 0, 5 * sizeof(Stack));
std::memset(ss-2, 0, 5 * sizeof(Stack));
- searching = false;
- notify_one(); // Wake up main thread if is sleeping waiting for us
-
if (!isMainThread)
return;
if (!isMainThread)
return;
ss->ply = (ss-1)->ply + 1;
// Check for available remaining time
ss->ply = (ss-1)->ply + 1;
// Check for available remaining time
- if (thisThread->resetCallsCnt.load(std::memory_order_relaxed))
+ if (thisThread->resetCalls.load(std::memory_order_relaxed))
- thisThread->resetCallsCnt = false;
+ thisThread->resetCalls = false;
thisThread->callsCnt = 0;
}
if (++thisThread->callsCnt > 4096)
{
for (Thread* th : Threads)
thisThread->callsCnt = 0;
}
if (++thisThread->callsCnt > 4096)
{
for (Thread* th : Threads)
- th->resetCallsCnt = true;
ThreadPool Threads; // Global object
ThreadPool Threads; // Global object
+// Thread constructor makes some init and launches the thread that will go to
+// sleep in idle_loop().
- // Helpers to launch a thread after creation and joining before delete. Outside the
- // Thread constructor and destructor because the object must be fully initialized
- // when start_routine (and hence virtual idle_loop) is called and when joining.
-
- template<typename T> T* new_thread() {
- std::thread* th = new T;
- *th = std::thread(&T::idle_loop, (T*)th); // Will go to sleep
- return (T*)th;
- }
-
- void delete_thread(ThreadBase* th) {
-
- th->mutex.lock();
- th->exit = true; // Search must be already finished
- th->mutex.unlock();
-
- th->notify_one();
- th->join(); // Wait for thread termination
- delete th;
- }
+ searching = true; // Avoid a race with start_thinking()
+ exit = resetCalls = false;
+ maxPly = callsCnt = 0;
+ history.clear();
+ counterMoves.clear();
+ idx = Threads.size(); // Starts from 0
+ std::thread::operator=(std::thread(&Thread::idle_loop, this));
-// ThreadBase::notify_one() wakes up the thread when there is some work to do
+// Thread destructor waits for thread termination before deleting
-void ThreadBase::notify_one() {
- std::unique_lock<Mutex> lk(mutex);
- sleepCondition.notify_one();
-}
+ mutex.lock();
+ exit = true; // Search must be already finished
+ mutex.unlock();
+ notify_one();
+ std::thread::join(); // Wait for thread termination
+}
-// ThreadBase::wait() set the thread to sleep until 'condition' turns true
-void ThreadBase::wait(std::atomic_bool& condition) {
+// Thread::join() waits for the thread to finish searching
+void Thread::join() {
std::unique_lock<Mutex> lk(mutex);
std::unique_lock<Mutex> lk(mutex);
- sleepCondition.wait(lk, [&]{ return bool(condition); });
+ sleepCondition.wait(lk, [&]{ return !searching; });
-// ThreadBase::wait_while() set the thread to sleep until 'condition' turns false
-void ThreadBase::wait_while(std::atomic_bool& condition) {
+// Thread::notify_one() wakes up the thread when there is some work to do
+
+void Thread::notify_one() {
std::unique_lock<Mutex> lk(mutex);
std::unique_lock<Mutex> lk(mutex);
- sleepCondition.wait(lk, [&]{ return !condition; });
+ sleepCondition.notify_one();
-// Thread constructor makes some init but does not launch any execution thread,
-// which will be started only when the constructor returns.
+// Thread::wait() set the thread to sleep until 'condition' turns true
+void Thread::wait(std::atomic_bool& condition) {
- searching = resetCallsCnt = false;
- maxPly = callsCnt = 0;
- history.clear();
- counterMoves.clear();
- idx = Threads.size(); // Starts from 0
+ std::unique_lock<Mutex> lk(mutex);
+ sleepCondition.wait(lk, [&]{ return bool(condition); });
{
std::unique_lock<Mutex> lk(mutex);
{
std::unique_lock<Mutex> lk(mutex);
- while (!searching && !exit)
- sleepCondition.wait(lk);
- lk.unlock();
-
- if (!exit && searching)
- search();
- }
-}
-
-
-// MainThread::idle_loop() is where the main thread is parked waiting to be started
-// when there is a new search. The main thread will launch all the slave threads.
-
-void MainThread::idle_loop() {
-
- while (!exit)
- {
- std::unique_lock<Mutex> lk(mutex);
-
- thinking = false;
-
- while (!thinking && !exit)
+ while (!searching && !exit)
- sleepCondition.notify_one(); // Wake up the UI thread if needed
+ sleepCondition.notify_one(); // Wake up main thread if needed
sleepCondition.wait(lk);
}
lk.unlock();
sleepCondition.wait(lk);
}
lk.unlock();
+ if (!exit && searching)
+ search();
-// MainThread::join() waits for main thread to finish thinking
-
-void MainThread::join() {
-
- std::unique_lock<Mutex> lk(mutex);
- sleepCondition.wait(lk, [&]{ return !thinking; });
-}
-
-
// ThreadPool::init() is called at startup to create and launch requested threads,
// that will go immediately to sleep. We cannot use a constructor because Threads
// is a static object and we need a fully initialized engine at this point due to
// ThreadPool::init() is called at startup to create and launch requested threads,
// that will go immediately to sleep. We cannot use a constructor because Threads
// is a static object and we need a fully initialized engine at this point due to
void ThreadPool::init() {
void ThreadPool::init() {
- push_back(new_thread<MainThread>());
+ push_back(new MainThread);
void ThreadPool::exit() {
for (Thread* th : *this)
void ThreadPool::exit() {
for (Thread* th : *this)
clear(); // Get rid of stale pointers
}
clear(); // Get rid of stale pointers
}
assert(requested > 0);
while (size() < requested)
assert(requested > 0);
while (size() < requested)
- push_back(new_thread<Thread>());
while (size() > requested)
{
while (size() > requested)
{
void ThreadPool::start_thinking(const Position& pos, const LimitsType& limits,
StateStackPtr& states) {
void ThreadPool::start_thinking(const Position& pos, const LimitsType& limits,
StateStackPtr& states) {
+ for (Thread* th : Threads)
+ th->join();
Signals.stopOnPonderhit = Signals.firstRootMove = false;
Signals.stop = Signals.failedLowAtRoot = false;
Signals.stopOnPonderhit = Signals.firstRootMove = false;
Signals.stop = Signals.failedLowAtRoot = false;
|| std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m))
main()->rootMoves.push_back(RootMove(m));
|| std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m))
main()->rootMoves.push_back(RootMove(m));
- main()->thinking = true;
- main()->notify_one(); // Wake up main thread: 'thinking' must be already set
+ main()->searching = true;
+ main()->notify_one(); // Wake up main thread: 'searching' must be already set
#include "thread_win32.h"
#include "thread_win32.h"
-/// ThreadBase struct is the base of the hierarchy from where we derive all the
-/// specialized thread classes.
+/// Thread struct keeps together all the thread related stuff. 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 ThreadBase : public std::thread {
+struct Thread : public std::thread {
- ThreadBase() { exit = false; }
- virtual ~ThreadBase() = default;
- virtual void idle_loop() = 0;
+ Thread();
+ virtual ~Thread();
+ virtual void search();
+ void idle_loop();
+ void join();
void notify_one();
void wait(std::atomic_bool& b);
void notify_one();
void wait(std::atomic_bool& b);
- void wait_while(std::atomic_bool& b);
+ std::atomic_bool exit, searching, resetCalls;
Mutex mutex;
ConditionVariable sleepCondition;
Mutex mutex;
ConditionVariable sleepCondition;
- std::atomic_bool exit;
-};
-
-
-/// Thread struct keeps together all the thread related stuff like locks, state,
-/// history and countermoves tables. 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 : public ThreadBase {
-
- Thread();
- virtual void idle_loop();
- void search(bool isMainThread = false);
Pawns::Table pawnsTable;
Material::Table materialTable;
Endgames endgames;
size_t idx, PVIdx;
int maxPly, callsCnt;
Pawns::Table pawnsTable;
Material::Table materialTable;
Endgames endgames;
size_t idx, PVIdx;
int maxPly, callsCnt;
- std::atomic_bool searching, resetCallsCnt;
Position rootPos;
Search::RootMoveVector rootMoves;
Position rootPos;
Search::RootMoveVector rootMoves;
/// MainThread is a derived classes used to characterize the the main one
struct MainThread : public Thread {
/// MainThread is a derived classes used to characterize the the main one
struct MainThread : public Thread {
- MainThread() { thinking = true; } // Avoid a race with start_thinking()
- virtual void idle_loop();
- void join();
- void think();
- std::atomic_bool thinking;