From: Marco Costalba Date: Sat, 24 Mar 2012 20:36:33 +0000 (+0100) Subject: Use std::vector to store threads X-Git-Url: https://git.sesse.net/?p=stockfish;a=commitdiff_plain;h=41561c9bb80a176f9fce169975fcb553340499fc Use std::vector to store threads We store pointers instead of Thread objects because Thread is not copy-constructible nor copy-assignable and default ones are not suitable. So we cannot store directly in a std::vector. No functional change. Signed-off-by: Marco Costalba --- diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 2903c4b3..b2cae94c 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -357,13 +357,12 @@ namespace { template Value do_evaluate(const Position& pos, Value& margin) { + assert(!pos.in_check()); + EvalInfo ei; Value margins[2]; Score score, mobilityWhite, mobilityBlack; - assert(pos.thread() >= 0 && pos.thread() < MAX_THREADS); - assert(!pos.in_check()); - // Initialize score by reading the incrementally updated scores included // in the position object (material + piece square tables). score = pos.value(); diff --git a/src/search.cpp b/src/search.cpp index cc82af7d..a76a9521 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -310,8 +310,7 @@ void Search::think() { // We're ready to start searching. Call the iterative deepening loop function id_loop(pos); - // Stop timer and send all the slaves to sleep, if not already sleeping - Threads.set_timer(0); + Threads.set_timer(0); // Stop timer Threads.sleep(); if (Options["Use Search Log"]) diff --git a/src/thread.cpp b/src/thread.cpp index 0d11a2d5..031ee848 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -53,13 +53,16 @@ namespace { extern "C" { } } +// Thread c'tor creates and launches the OS thread, that will go immediately to +// sleep. + Thread::Thread(int id) { - threadID = id; - do_sleep = (id != 0); // Avoid a race with start_thinking() is_searching = do_exit = false; maxPly = splitPointsCnt = 0; curSplitPoint = NULL; + threadID = id; + do_sleep = (id != 0); // Avoid a race with start_thinking() lock_init(sleepLock); cond_init(sleepCond); @@ -75,6 +78,8 @@ Thread::Thread(int id) { } +// Thread d'tor will wait for thread termination before to return. + Thread::~Thread() { assert(do_sleep); @@ -205,42 +210,49 @@ bool Thread::is_available_to(int master) const { // read_uci_options() updates internal threads parameters from the corresponding -// UCI options. It is called before to start a new search. +// UCI options and creates/destroys threads to match the requested number. Thread +// objects are dynamically allocated to avoid creating in advance all possible +// threads, with included pawns and material tables, if only few are used. void ThreadsManager::read_uci_options() { maxThreadsPerSplitPoint = Options["Max Threads per Split Point"]; minimumSplitDepth = Options["Min Split Depth"] * ONE_PLY; useSleepingThreads = Options["Use Sleeping Threads"]; - activeThreads = Options["Threads"]; - - // Dynamically allocate Thread object according to the number of - // active threads. This avoids preallocating memory for all possible - // threads if only few are used. - for (int i = 0; i < MAX_THREADS; i++) - if (i < activeThreads && !threads[i]) - threads[i] = new Thread(i); - else if (i >= activeThreads && threads[i]) - { - delete threads[i]; - threads[i] = NULL; - } + int requested = Options["Threads"]; + + while (size() < requested) + threads.push_back(new Thread(size())); + + while (size() > requested) + { + delete threads.back(); + threads.pop_back(); + } } +// wake_up() is called before a new search to start the threads that are waiting +// on the sleep condition. If useSleepingThreads is set threads will be woken up +// at split time. + void ThreadsManager::wake_up() { - for (int i = 0; i < activeThreads; i++) + for (int i = 0; i < size(); i++) { threads[i]->do_sleep = false; - threads[i]->wake_up(); + + if (!useSleepingThreads) + threads[i]->wake_up(); } } +// sleep() is called after the search to ask threads to wait on sleep condition + void ThreadsManager::sleep() { - for (int i = 0; i < activeThreads; i++) + for (int i = 0; i < size(); i++) threads[i]->do_sleep = true; } @@ -253,17 +265,16 @@ void ThreadsManager::init() { cond_init(sleepCond); lock_init(splitLock); timer = new Thread(MAX_THREADS); - read_uci_options(); // Creates at least main thread + read_uci_options(); // Creates at least the main thread } -// exit() is called to cleanly terminate the threads when the program finishes +// exit() is called to cleanly terminate the threads before the program finishes void ThreadsManager::exit() { - for (int i = 0; i < MAX_THREADS; i++) - if (threads[i]) - delete threads[i]; + for (int i = 0; i < size(); i++) + delete threads[i]; delete timer; lock_destroy(splitLock); @@ -276,9 +287,9 @@ void ThreadsManager::exit() { bool ThreadsManager::available_slave_exists(int master) const { - assert(master >= 0 && master < activeThreads); + assert(master >= 0 && master < size()); - for (int i = 0; i < activeThreads; i++) + for (int i = 0; i < size(); i++) if (threads[i]->is_available_to(master)) return true; @@ -305,8 +316,6 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta, assert(alpha < beta); assert(beta <= VALUE_INFINITE); assert(depth > DEPTH_ZERO); - assert(pos.thread() >= 0 && pos.thread() < activeThreads); - assert(activeThreads > 1); int master = pos.thread(); Thread& masterThread = *threads[master]; @@ -345,7 +354,7 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta, lock_grab(sp->lock); lock_grab(splitLock); - for (int i = 0; i < activeThreads && !Fake; i++) + for (int i = 0; i < size() && !Fake; ++i) if (threads[i]->is_available_to(master)) { sp->slavesMask |= 1ULL << i; @@ -418,7 +427,7 @@ void ThreadsManager::set_timer(int msec) { void ThreadsManager::start_thinking(const Position& pos, const LimitsType& limits, const std::set& searchMoves, bool async) { - Thread& main = *threads[0]; + Thread& main = *threads.front(); lock_grab(main.sleepLock); @@ -458,7 +467,7 @@ void ThreadsManager::start_thinking(const Position& pos, const LimitsType& limit void ThreadsManager::stop_thinking() { - Thread& main = *threads[0]; + Thread& main = *threads.front(); Search::Signals.stop = true; diff --git a/src/thread.h b/src/thread.h index a88bb6d3..6744ef31 100644 --- a/src/thread.h +++ b/src/thread.h @@ -21,6 +21,7 @@ #define THREAD_H_INCLUDED #include +#include #include "material.h" #include "movepick.h" @@ -64,8 +65,12 @@ struct SplitPoint { /// 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 { +class Thread { + Thread(const Thread&); // Only declared to disable the default ones + Thread& operator=(const Thread&); // that are not suitable in this case. + +public: Thread(int id); ~Thread(); @@ -103,13 +108,13 @@ class ThreadsManager { static storage duration are automatically set to zero before enter main() */ public: - Thread& operator[](int threadID) { return *threads[threadID]; } void init(); void exit(); + Thread& operator[](int id) { return *threads[id]; } bool use_sleeping_threads() const { return useSleepingThreads; } int min_split_depth() const { return minimumSplitDepth; } - int size() const { return activeThreads; } + int size() const { return (int)threads.size(); } void wake_up(); void sleep(); @@ -124,15 +129,14 @@ public: Value split(Position& pos, Search::Stack* ss, Value alpha, Value beta, Value bestValue, Move* bestMove, Depth depth, Move threatMove, int moveCount, MovePicker* mp, int nodeType); private: - friend struct Thread; + friend class Thread; + std::vector threads; Thread* timer; - Thread* threads[MAX_THREADS]; Lock splitLock; WaitCondition sleepCond; Depth minimumSplitDepth; int maxThreadsPerSplitPoint; - int activeThreads; bool useSleepingThreads; };