From: Marco Costalba Date: Sat, 24 Mar 2012 19:10:13 +0000 (+0100) Subject: Refactor Thread class X-Git-Url: https://git.sesse.net/?p=stockfish;a=commitdiff_plain;h=553655eb073cdd59c726dd77fcf368d499029467 Refactor Thread class Associate platform OS thread to the Thread class instead of creating it from ThreadsManager. No functional change. Signed-off-by: Marco Costalba --- diff --git a/src/material.cpp b/src/material.cpp index 7369bca9..e2c64ff7 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -84,12 +84,6 @@ namespace { } // namespace -/// MaterialInfoTable c'tor and d'tor allocate and free the space for Endgames - -void MaterialInfoTable::init() { Base::init(); if (!funcs) funcs = new Endgames(); } -MaterialInfoTable::~MaterialInfoTable() { delete funcs; } - - /// MaterialInfoTable::material_info() takes a position object as input, /// computes or looks up a MaterialInfo object, and returns a pointer to it. /// If the material configuration is not already present in the table, it diff --git a/src/material.h b/src/material.h index 45bfe8b0..6f844926 100644 --- a/src/material.h +++ b/src/material.h @@ -72,8 +72,9 @@ private: class MaterialInfoTable : public SimpleHash { public: - ~MaterialInfoTable(); - void init(); + MaterialInfoTable() : funcs(new Endgames()) {} + ~MaterialInfoTable() { delete funcs; } + MaterialInfo* material_info(const Position& pos) const; static Phase game_phase(const Position& pos); diff --git a/src/platform.h b/src/platform.h index 26c3abfb..f9739c69 100644 --- a/src/platform.h +++ b/src/platform.h @@ -65,7 +65,7 @@ typedef void*(*start_fn)(void*); # define cond_signal(x) pthread_cond_signal(&(x)) # define cond_wait(x,y) pthread_cond_wait(&(x),&(y)) # define cond_timedwait(x,y,z) pthread_cond_timedwait(&(x),&(y),z) -# define thread_create(x,f,id) !pthread_create(&(x),NULL,(start_fn)f,&(id)) +# define thread_create(x,f,t) !pthread_create(&(x),NULL,(start_fn)f,t) # define thread_join(x) pthread_join(x, NULL) #else // Windows and MinGW @@ -101,7 +101,7 @@ typedef HANDLE ThreadHandle; # define cond_signal(x) SetEvent(x) # define cond_wait(x,y) { lock_release(y); WaitForSingleObject(x, INFINITE); lock_grab(y); } # define cond_timedwait(x,y,z) { lock_release(y); WaitForSingleObject(x,z); lock_grab(y); } -# define thread_create(x,f,id) (x = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)f,&(id),0,NULL), x != NULL) +# define thread_create(x,f,t) (x = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)f,t,0,NULL), x != NULL) # define thread_join(x) { WaitForSingleObject(x, INFINITE); CloseHandle(x); } #endif diff --git a/src/thread.cpp b/src/thread.cpp index 1913aee4..0d11a2d5 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -53,6 +53,45 @@ namespace { extern "C" { } } +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; + + lock_init(sleepLock); + cond_init(sleepCond); + + for (int j = 0; j < MAX_SPLITPOINTS_PER_THREAD; j++) + lock_init(splitPoints[j].lock); + + if (!thread_create(handle, start_routine, this)) + { + std::cerr << "Failed to create thread number " << id << std::endl; + ::exit(EXIT_FAILURE); + } +} + + +Thread::~Thread() { + + assert(do_sleep); + + do_exit = true; // Search must be already finished + wake_up(); + + thread_join(handle); // Wait for thread termination + + lock_destroy(sleepLock); + cond_destroy(sleepCond); + + for (int j = 0; j < MAX_SPLITPOINTS_PER_THREAD; j++) + lock_destroy(splitPoints[j].lock); +} + + // Thread::timer_loop() is where the timer thread waits maxPly milliseconds and // then calls do_timer_event(). If maxPly is 0 thread sleeps until is woken up. extern void check_time(); @@ -175,15 +214,16 @@ void ThreadsManager::read_uci_options() { useSleepingThreads = Options["Use Sleeping Threads"]; activeThreads = Options["Threads"]; - // Dynamically allocate pawn and material hash tables according to the - // number of active threads. This avoids preallocating memory for all - // possible threads if only few are used. + // 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) + if (i < activeThreads && !threads[i]) + threads[i] = new Thread(i); + else if (i >= activeThreads && threads[i]) { - threads[i].pawnTable.init(); - threads[i].materialTable.init(); - threads[i].maxPly = 0; + delete threads[i]; + threads[i] = NULL; } } @@ -192,8 +232,8 @@ void ThreadsManager::wake_up() { for (int i = 0; i < activeThreads; i++) { - threads[i].do_sleep = false; - threads[i].wake_up(); + threads[i]->do_sleep = false; + threads[i]->wake_up(); } } @@ -201,7 +241,7 @@ void ThreadsManager::wake_up() { void ThreadsManager::sleep() { for (int i = 0; i < activeThreads; i++) - threads[i].do_sleep = true; + threads[i]->do_sleep = true; } @@ -210,34 +250,10 @@ void ThreadsManager::sleep() { void ThreadsManager::init() { - read_uci_options(); - - cond_init(sleepCond); - lock_init(splitLock); - - // Allocate main thread tables to call evaluate() also when not searching - threads[0].pawnTable.init(); - threads[0].materialTable.init(); - - // Create and launch all the threads, threads will go immediately to sleep - for (int i = 0; i <= MAX_THREADS; i++) - { - threads[i].is_searching = false; - threads[i].do_sleep = (i != 0); // Avoid a race with start_thinking() - threads[i].threadID = i; - - lock_init(threads[i].sleepLock); - cond_init(threads[i].sleepCond); - - for (int j = 0; j < MAX_SPLITPOINTS_PER_THREAD; j++) - lock_init(threads[i].splitPoints[j].lock); - - if (!thread_create(threads[i].handle, start_routine, threads[i])) - { - std::cerr << "Failed to create thread number " << i << std::endl; - ::exit(EXIT_FAILURE); - } - } + cond_init(sleepCond); + lock_init(splitLock); + timer = new Thread(MAX_THREADS); + read_uci_options(); // Creates at least main thread } @@ -245,22 +261,11 @@ void ThreadsManager::init() { void ThreadsManager::exit() { - for (int i = 0; i <= MAX_THREADS; i++) - { - assert(threads[i].do_sleep); - - threads[i].do_exit = true; // Search must be already finished - threads[i].wake_up(); - - thread_join(threads[i].handle); // Wait for thread termination - - lock_destroy(threads[i].sleepLock); - cond_destroy(threads[i].sleepCond); - - for (int j = 0; j < MAX_SPLITPOINTS_PER_THREAD; j++) - lock_destroy(threads[i].splitPoints[j].lock); - } + for (int i = 0; i < MAX_THREADS; i++) + if (threads[i]) + delete threads[i]; + delete timer; lock_destroy(splitLock); cond_destroy(sleepCond); } @@ -274,7 +279,7 @@ bool ThreadsManager::available_slave_exists(int master) const { assert(master >= 0 && master < activeThreads); for (int i = 0; i < activeThreads; i++) - if (threads[i].is_available_to(master)) + if (threads[i]->is_available_to(master)) return true; return false; @@ -304,7 +309,7 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta, assert(activeThreads > 1); int master = pos.thread(); - Thread& masterThread = threads[master]; + Thread& masterThread = *threads[master]; if (masterThread.splitPointsCnt >= MAX_SPLITPOINTS_PER_THREAD) return bestValue; @@ -341,14 +346,14 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta, lock_grab(splitLock); for (int i = 0; i < activeThreads && !Fake; i++) - if (threads[i].is_available_to(master)) + if (threads[i]->is_available_to(master)) { sp->slavesMask |= 1ULL << i; - threads[i].curSplitPoint = sp; - threads[i].is_searching = true; // Slave leaves idle_loop() + threads[i]->curSplitPoint = sp; + threads[i]->is_searching = true; // Slave leaves idle_loop() if (useSleepingThreads) - threads[i].wake_up(); + threads[i]->wake_up(); if (++slavesCnt + 1 >= maxThreadsPerSplitPoint) // Master is always included break; @@ -399,12 +404,10 @@ template Value ThreadsManager::split(Position&, Stack*, Value, Value, Valu void ThreadsManager::set_timer(int msec) { - Thread& timer = threads[MAX_THREADS]; - - lock_grab(timer.sleepLock); - timer.maxPly = msec; - cond_signal(timer.sleepCond); // Wake up and restart the timer - lock_release(timer.sleepLock); + lock_grab(timer->sleepLock); + timer->maxPly = msec; + cond_signal(timer->sleepCond); // Wake up and restart the timer + lock_release(timer->sleepLock); } @@ -415,7 +418,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[0]; lock_grab(main.sleepLock); @@ -455,7 +458,7 @@ void ThreadsManager::start_thinking(const Position& pos, const LimitsType& limit void ThreadsManager::stop_thinking() { - Thread& main = threads[0]; + Thread& main = *threads[0]; Search::Signals.stop = true; diff --git a/src/thread.h b/src/thread.h index 6f231363..a88bb6d3 100644 --- a/src/thread.h +++ b/src/thread.h @@ -66,6 +66,9 @@ struct SplitPoint { struct Thread { + Thread(int id); + ~Thread(); + void wake_up(); bool cutoff_occurred() const; bool is_available_to(int master) const; @@ -100,7 +103,7 @@ class ThreadsManager { static storage duration are automatically set to zero before enter main() */ public: - Thread& operator[](int threadID) { return threads[threadID]; } + Thread& operator[](int threadID) { return *threads[threadID]; } void init(); void exit(); @@ -123,7 +126,8 @@ public: private: friend struct Thread; - Thread threads[MAX_THREADS + 1]; // Last one is used as a timer + Thread* timer; + Thread* threads[MAX_THREADS]; Lock splitLock; WaitCondition sleepCond; Depth minimumSplitDepth; diff --git a/src/tt.h b/src/tt.h index 39c161df..2cc1a3c5 100644 --- a/src/tt.h +++ b/src/tt.h @@ -146,10 +146,7 @@ struct SimpleHash { typedef SimpleHash Base; - void init() { - - if (entries) - return; + SimpleHash() { entries = new (std::nothrow) Entry[HashSize]; if (!entries)