X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fthread.cpp;h=3b7a10eeed31a2dc33415d2f5cbd6fe7037cc7c8;hp=cb0ab5e9c258eea998fe9c5892e77e88562308c2;hb=7fb6fd2f558c9e2967fb393238d1dbe063f2d277;hpb=f80c50bcddfd02c1b93dcde067d6a7362dda53a2 diff --git a/src/thread.cpp b/src/thread.cpp index cb0ab5e9..3b7a10ee 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -17,8 +17,10 @@ along with this program. If not, see . */ +#include #include +#include "movegen.h" #include "search.h" #include "thread.h" #include "ucioption.h" @@ -34,7 +36,7 @@ namespace { extern "C" { // and last thread are special. First one is the main search thread while the // last one mimics a timer, they run in main_loop() and timer_loop(). -#if defined(_MSC_VER) +#if defined(_WIN32) || defined(_WIN64) DWORD WINAPI start_routine(LPVOID thread) { #else void* start_routine(void* thread) { @@ -62,9 +64,9 @@ namespace { extern "C" { void Thread::wake_up() { - lock_grab(&sleepLock); - cond_signal(&sleepCond); - lock_release(&sleepLock); + lock_grab(sleepLock); + cond_signal(sleepCond); + lock_release(sleepLock); } @@ -95,12 +97,11 @@ bool Thread::is_available_to(int master) const { // Make a local copy to be sure doesn't become zero under our feet while // testing next condition and so leading to an out of bound access. - int localActiveSplitPoints = activeSplitPoints; + int sp_count = activeSplitPoints; // No active split points means that the thread is available as a slave for any // other thread otherwise apply the "helpful master" concept if possible. - if ( !localActiveSplitPoints - || splitPoints[localActiveSplitPoints - 1].is_slave[master]) + if (!sp_count || (splitPoints[sp_count - 1].slavesMask & (1ULL << master))) return true; return false; @@ -151,17 +152,17 @@ void ThreadsManager::set_size(int cnt) { void ThreadsManager::init() { // Initialize sleep condition and lock used by thread manager - cond_init(&sleepCond); - lock_init(&threadsLock); + cond_init(sleepCond); + lock_init(threadsLock); // Initialize thread's sleep conditions and split point locks for (int i = 0; i <= MAX_THREADS; i++) { - lock_init(&threads[i].sleepLock); - cond_init(&threads[i].sleepCond); + lock_init(threads[i].sleepLock); + cond_init(threads[i].sleepCond); for (int j = 0; j < MAX_ACTIVE_SPLIT_POINTS; j++) - lock_init(&(threads[i].splitPoints[j].lock)); + lock_init(threads[i].splitPoints[j].lock); } // Allocate main thread tables to call evaluate() also when not searching @@ -175,14 +176,7 @@ void ThreadsManager::init() { threads[i].do_sleep = (i != 0); // Avoid a race with start_thinking() threads[i].threadID = i; -#if defined(_MSC_VER) - threads[i].handle = CreateThread(NULL, 0, start_routine, &threads[i], 0, NULL); - bool ok = (threads[i].handle != NULL); -#else - bool ok = !pthread_create(&threads[i].handle, NULL, start_routine, &threads[i]); -#endif - - if (!ok) + if (!thread_create(threads[i].handle, start_routine, threads[i])) { std::cerr << "Failed to create thread number " << i << std::endl; ::exit(EXIT_FAILURE); @@ -195,29 +189,25 @@ void ThreadsManager::init() { void ThreadsManager::exit() { + assert(threads[0].is_searching == false); + for (int i = 0; i <= MAX_THREADS; i++) { - threads[i].do_terminate = true; // Search must be already finished + threads[i].do_exit = true; // Search must be already finished threads[i].wake_up(); - // Wait for thread termination -#if defined(_MSC_VER) - WaitForSingleObject(threads[i].handle, INFINITE); - CloseHandle(threads[i].handle); -#else - pthread_join(threads[i].handle, NULL); -#endif + thread_join(threads[i].handle); // Wait for thread termination // Now we can safely destroy associated locks and wait conditions - lock_destroy(&threads[i].sleepLock); - cond_destroy(&threads[i].sleepCond); + lock_destroy(threads[i].sleepLock); + cond_destroy(threads[i].sleepCond); for (int j = 0; j < MAX_ACTIVE_SPLIT_POINTS; j++) - lock_destroy(&(threads[i].splitPoints[j].lock)); + lock_destroy(threads[i].splitPoints[j].lock); } - lock_destroy(&threadsLock); - cond_destroy(&sleepCond); + lock_destroy(threadsLock); + cond_destroy(sleepCond); } @@ -236,19 +226,6 @@ bool ThreadsManager::available_slave_exists(int master) const { } -// split_point_finished() checks if all the slave threads of a given split -// point have finished searching. - -bool ThreadsManager::split_point_finished(SplitPoint* sp) const { - - for (int i = 0; i < activeThreads; i++) - if (sp->is_slave[i]) - return false; - - return true; -} - - // split() does the actual work of distributing the work at a node between // several available threads. If it does not succeed in splitting the node // (because no idle threads are available, or because we have no unused split @@ -285,6 +262,7 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta, sp->parent = masterThread.splitPoint; sp->master = master; sp->is_betaCutoff = false; + sp->slavesMask = (1ULL << master); sp->depth = depth; sp->threatMove = threatMove; sp->alpha = alpha; @@ -297,9 +275,6 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta, sp->nodes = 0; sp->ss = ss; - for (i = 0; i < activeThreads; i++) - sp->is_slave[i] = false; - // If we are here it means we are not available assert(masterThread.is_searching); @@ -308,23 +283,27 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta, // Try to allocate available threads and ask them to start searching setting // is_searching flag. This must be done under lock protection to avoid concurrent // allocation of the same slave by another master. - lock_grab(&threadsLock); + lock_grab(threadsLock); + lock_grab(sp->lock); // To protect sp->slaves_mask - for (i = 0; !Fake && i < activeThreads && workersCnt < maxThreadsPerSplitPoint; i++) + for (i = 0; !Fake && i < activeThreads; i++) if (threads[i].is_available_to(master)) { - workersCnt++; - sp->is_slave[i] = true; + sp->slavesMask |= (1ULL << i); threads[i].splitPoint = sp; - // This makes the slave to exit from idle_loop() + // Allocate the slave and make it exit from idle_loop() threads[i].is_searching = true; if (useSleepingThreads) threads[i].wake_up(); + + if (++workersCnt >= maxThreadsPerSplitPoint) + break; } - lock_release(&threadsLock); + lock_release(sp->lock); + lock_release(threadsLock); // We failed to allocate even one slave, return if (!Fake && workersCnt == 1) @@ -347,16 +326,18 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta, // We have returned from the idle loop, which means that all threads are // finished. Note that changing state and decreasing activeSplitPoints is done // under lock protection to avoid a race with Thread::is_available_to(). - lock_grab(&threadsLock); + lock_grab(threadsLock); + lock_grab(sp->lock); // To protect sp->nodes + masterThread.is_searching = true; masterThread.activeSplitPoints--; - - lock_release(&threadsLock); - masterThread.splitPoint = sp->parent; pos.set_nodes_searched(pos.nodes_searched() + sp->nodes); + lock_release(sp->lock); + lock_release(threadsLock); + return sp->bestValue; } @@ -371,11 +352,11 @@ extern void check_time(); void Thread::timer_loop() { - while (!do_terminate) + while (!do_exit) { - lock_grab(&sleepLock); - timed_wait(&sleepCond, &sleepLock, maxPly ? maxPly : INT_MAX); - lock_release(&sleepLock); + lock_grab(sleepLock); + timed_wait(sleepCond, sleepLock, maxPly ? maxPly : INT_MAX); + lock_release(sleepLock); check_time(); } } @@ -388,10 +369,10 @@ void ThreadsManager::set_timer(int msec) { Thread& timer = threads[MAX_THREADS]; - lock_grab(&timer.sleepLock); + lock_grab(timer.sleepLock); timer.maxPly = msec; - cond_signal(&timer.sleepCond); // Wake up and restart the timer - lock_release(&timer.sleepLock); + cond_signal(timer.sleepCond); // Wake up and restart the timer + lock_release(timer.sleepLock); } @@ -402,25 +383,25 @@ void Thread::main_loop() { while (true) { - lock_grab(&sleepLock); + lock_grab(sleepLock); do_sleep = true; // Always return to sleep after a search is_searching = false; - while (do_sleep && !do_terminate) + while (do_sleep && !do_exit) { - cond_signal(&Threads.sleepCond); // Wake up UI thread if needed - cond_wait(&sleepCond, &sleepLock); + cond_signal(Threads.sleepCond); // Wake up UI thread if needed + cond_wait(sleepCond, sleepLock); } is_searching = true; - lock_release(&sleepLock); + lock_release(sleepLock); - if (do_terminate) + if (do_exit) return; - think(); // This is the search entry point + Search::think(); } } @@ -431,31 +412,38 @@ void Thread::main_loop() { // the search to finish. void ThreadsManager::start_thinking(const Position& pos, const LimitsType& limits, - const std::vector& searchMoves, bool asyncMode) { + const std::set& searchMoves, bool async) { Thread& main = threads[0]; - lock_grab(&main.sleepLock); + lock_grab(main.sleepLock); // Wait main thread has finished before to launch a new search while (!main.do_sleep) - cond_wait(&sleepCond, &main.sleepLock); + cond_wait(sleepCond, main.sleepLock); // Copy input arguments to initialize the search RootPosition.copy(pos, 0); Limits = limits; - SearchMoves = searchMoves; + RootMoves.clear(); + + // Populate RootMoves with all the legal moves (default) or, if a searchMoves + // set is given, with the subset of legal moves to search. + for (MoveList ml(pos); !ml.end(); ++ml) + if (searchMoves.empty() || searchMoves.count(ml.move())) + RootMoves.push_back(RootMove(ml.move())); // Reset signals before to start the new search - memset((void*)&Signals, 0, sizeof(Signals)); + Signals.stopOnPonderhit = Signals.firstRootMove = false; + Signals.stop = Signals.failedLowAtRoot = false; main.do_sleep = false; - cond_signal(&main.sleepCond); // Wake up main thread and start searching + cond_signal(main.sleepCond); // Wake up main thread and start searching - if (!asyncMode) + if (!async) while (!main.do_sleep) - cond_wait(&sleepCond, &main.sleepLock); + cond_wait(sleepCond, main.sleepLock); - lock_release(&main.sleepLock); + lock_release(main.sleepLock); } @@ -469,14 +457,14 @@ void ThreadsManager::stop_thinking() { Search::Signals.stop = true; - lock_grab(&main.sleepLock); + lock_grab(main.sleepLock); - cond_signal(&main.sleepCond); // In case is waiting for stop or ponderhit + cond_signal(main.sleepCond); // In case is waiting for stop or ponderhit while (!main.do_sleep) - cond_wait(&sleepCond, &main.sleepLock); + cond_wait(sleepCond, main.sleepLock); - lock_release(&main.sleepLock); + lock_release(main.sleepLock); } @@ -493,10 +481,10 @@ void ThreadsManager::wait_for_stop_or_ponderhit() { Thread& main = threads[0]; - lock_grab(&main.sleepLock); + lock_grab(main.sleepLock); while (!Signals.stop) - cond_wait(&main.sleepCond, &main.sleepLock); + cond_wait(main.sleepCond, main.sleepLock); - lock_release(&main.sleepLock); + lock_release(main.sleepLock); }