From: Marco Costalba Date: Fri, 24 Aug 2012 09:59:41 +0000 (+0100) Subject: Introduce struct Mutex and ConditionVariable X-Git-Url: https://git.sesse.net/?p=stockfish;a=commitdiff_plain;h=b6883c872d267cf464c575d2a901e117f6a97a84 Introduce struct Mutex and ConditionVariable To mimics C++11 std::mutex and std::condition_variable, also rename locks and condition variables to be more uniform across the classes. No functional change. Signed-off-by: Marco Costalba --- diff --git a/src/search.cpp b/src/search.cpp index 6586144d..b86b9559 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -819,7 +819,7 @@ split_point_start: // At split points actual search starts from here if (SpNode) { moveCount = ++sp->moveCount; - lock_release(sp->lock); + sp->mutex.unlock(); } else moveCount++; @@ -885,7 +885,7 @@ split_point_start: // At split points actual search starts from here && (!threatMove || !connected_threat(pos, move, threatMove))) { if (SpNode) - lock_grab(sp->lock); + sp->mutex.lock(); continue; } @@ -900,7 +900,7 @@ split_point_start: // At split points actual search starts from here if (futilityValue < beta) { if (SpNode) - lock_grab(sp->lock); + sp->mutex.lock(); continue; } @@ -910,7 +910,7 @@ split_point_start: // At split points actual search starts from here && pos.see_sign(move) < 0) { if (SpNode) - lock_grab(sp->lock); + sp->mutex.lock(); continue; } @@ -974,7 +974,7 @@ split_point_start: // At split points actual search starts from here // Step 18. Check for new best move if (SpNode) { - lock_grab(sp->lock); + sp->mutex.lock(); bestValue = sp->bestValue; alpha = sp->alpha; } @@ -1670,12 +1670,12 @@ void Thread::idle_loop() { } // Grab the lock to avoid races with Thread::wake_up() - lock_grab(sleepLock); + mutex.lock(); // If we are master and all slaves have finished don't go to sleep if (sp_master && !sp_master->slavesMask) { - lock_release(sleepLock); + mutex.unlock(); break; } @@ -1684,9 +1684,9 @@ void Thread::idle_loop() { // in the meanwhile, allocated us and sent the wake_up() call before we // had the chance to grab the lock. if (do_sleep || !is_searching) - cond_wait(sleepCond, sleepLock); + sleepCondition.wait(mutex); - lock_release(sleepLock); + mutex.unlock(); } // If this thread has been assigned work, launch a search @@ -1694,12 +1694,12 @@ void Thread::idle_loop() { { assert(!do_sleep && !do_exit); - lock_grab(Threads.splitLock); + Threads.mutex.lock(); assert(is_searching); SplitPoint* sp = curSplitPoint; - lock_release(Threads.splitLock); + Threads.mutex.unlock(); Stack ss[MAX_PLY_PLUS_2]; Position pos(*sp->pos, this); @@ -1707,7 +1707,7 @@ void Thread::idle_loop() { memcpy(ss, sp->ss - 1, 4 * sizeof(Stack)); (ss+1)->sp = sp; - lock_grab(sp->lock); + sp->mutex.lock(); if (sp->nodeType == Root) search(pos, ss+1, sp->alpha, sp->beta, sp->depth); @@ -1738,7 +1738,7 @@ void Thread::idle_loop() { // related data in a safe way becuase it could have been released under // our feet by the sp master. Also accessing other Thread objects is // unsafe because if we are exiting there is a chance are already freed. - lock_release(sp->lock); + sp->mutex.unlock(); } } } diff --git a/src/thread.cpp b/src/thread.cpp index fc938eb1..42ffe63a 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -52,12 +52,6 @@ Thread::Thread(Fn fn) { do_sleep = (fn != &Thread::main_loop); // Avoid a race with start_searching() - 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 " << idx << std::endl; @@ -74,14 +68,7 @@ Thread::~Thread() { 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); } @@ -93,9 +80,9 @@ void Thread::timer_loop() { while (!do_exit) { - lock_grab(sleepLock); - timed_wait(sleepCond, sleepLock, maxPly ? maxPly : INT_MAX); - lock_release(sleepLock); + mutex.lock(); + sleepCondition.wait_for(mutex, maxPly ? maxPly : INT_MAX); + mutex.unlock(); check_time(); } } @@ -108,18 +95,18 @@ void Thread::main_loop() { while (true) { - lock_grab(sleepLock); + mutex.lock(); do_sleep = true; // Always return to sleep after a search is_searching = false; while (do_sleep && !do_exit) { - cond_signal(Threads.sleepCond); // Wake up UI thread if needed - cond_wait(sleepCond, sleepLock); + Threads.sleepCondition.notify_one(); // Wake up UI thread if needed + sleepCondition.wait(mutex); } - lock_release(sleepLock); + mutex.unlock(); if (do_exit) return; @@ -136,9 +123,9 @@ void Thread::main_loop() { void Thread::wake_up() { - lock_grab(sleepLock); - cond_signal(sleepCond); - lock_release(sleepLock); + mutex.lock(); + sleepCondition.notify_one(); + mutex.unlock(); } @@ -153,9 +140,9 @@ void Thread::wait_for_stop_or_ponderhit() { Signals.stopOnPonderhit = true; - lock_grab(sleepLock); - while (!Signals.stop) cond_wait(sleepCond, sleepLock); - lock_release(sleepLock); + mutex.lock(); + while (!Signals.stop) sleepCondition.wait(mutex);; + mutex.unlock(); } @@ -201,8 +188,6 @@ bool Thread::is_available_to(Thread* master) const { void ThreadPool::init() { - cond_init(sleepCond); - lock_init(splitLock); timer = new Thread(&Thread::timer_loop); threads.push_back(new Thread(&Thread::main_loop)); read_uci_options(); @@ -217,8 +202,6 @@ ThreadPool::~ThreadPool() { delete threads[i]; delete timer; - lock_destroy(splitLock); - cond_destroy(sleepCond); } @@ -341,8 +324,8 @@ Value ThreadPool::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(sp.lock); - lock_grab(splitLock); + sp.mutex.lock(); + mutex.lock(); for (size_t i = 0; i < size() && !Fake; ++i) if (threads[i]->is_available_to(master)) @@ -360,8 +343,8 @@ Value ThreadPool::split(Position& pos, Stack* ss, Value alpha, Value beta, master->splitPointsCnt++; - lock_release(splitLock); - lock_release(sp.lock); + mutex.unlock(); + sp.mutex.unlock(); // Everything is set up. The master thread enters the idle loop, from which // it will instantly launch a search, because its is_searching flag is set. @@ -379,8 +362,8 @@ Value ThreadPool::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 setting is_searching and decreasing splitPointsCnt is // done under lock protection to avoid a race with Thread::is_available_to(). - lock_grab(sp.lock); // To protect sp.nodes - lock_grab(splitLock); + sp.mutex.lock(); // To protect sp.nodes + mutex.lock(); master->is_searching = true; master->splitPointsCnt--; @@ -388,8 +371,8 @@ Value ThreadPool::split(Position& pos, Stack* ss, Value alpha, Value beta, pos.set_nodes_searched(pos.nodes_searched() + sp.nodes); *bestMove = sp.bestMove; - lock_release(splitLock); - lock_release(sp.lock); + mutex.unlock(); + sp.mutex.unlock(); return sp.bestValue; } @@ -404,10 +387,10 @@ template Value ThreadPool::split(Position&, Stack*, Value, Value, Value, M void ThreadPool::set_timer(int msec) { - lock_grab(timer->sleepLock); + timer->mutex.lock(); timer->maxPly = msec; - cond_signal(timer->sleepCond); // Wake up and restart the timer - lock_release(timer->sleepLock); + timer->sleepCondition.notify_one(); // Wake up and restart the timer + timer->mutex.unlock(); } @@ -417,10 +400,10 @@ void ThreadPool::set_timer(int msec) { void ThreadPool::wait_for_search_finished() { Thread* t = main_thread(); - lock_grab(t->sleepLock); - cond_signal(t->sleepCond); // In case is waiting for stop or ponderhit - while (!t->do_sleep) cond_wait(sleepCond, t->sleepLock); - lock_release(t->sleepLock); + t->mutex.lock(); + t->sleepCondition.notify_one(); // In case is waiting for stop or ponderhit + while (!t->do_sleep) sleepCondition.wait(t->mutex); + t->mutex.unlock(); } diff --git a/src/thread.h b/src/thread.h index ad40a341..5feab000 100644 --- a/src/thread.h +++ b/src/thread.h @@ -31,6 +31,31 @@ const int MAX_THREADS = 32; const int MAX_SPLITPOINTS_PER_THREAD = 8; +struct Mutex { + Mutex() { lock_init(l); } + ~Mutex() { lock_destroy(l); } + + void lock() { lock_grab(l); } + void unlock() { lock_release(l); } + +private: + friend struct ConditionVariable; + + Lock l; +}; + +struct ConditionVariable { + ConditionVariable() { cond_init(c); } + ~ConditionVariable() { cond_destroy(c); } + + void wait(Mutex& m) { cond_wait(c, m.l); } + void wait_for(Mutex& m, int ms) { timed_wait(c, m.l, ms); } + void notify_one() { cond_signal(c); } + +private: + WaitCondition c; +}; + class Thread; struct SplitPoint { @@ -49,7 +74,7 @@ struct SplitPoint { SplitPoint* parent; // Shared data - Lock lock; + Mutex mutex; volatile uint64_t slavesMask; volatile int64_t nodes; volatile Value alpha; @@ -86,8 +111,8 @@ public: PawnTable pawnTable; size_t idx; int maxPly; - Lock sleepLock; - WaitCondition sleepCond; + Mutex mutex; + ConditionVariable sleepCondition; NativeHandle handle; Fn start_fn; SplitPoint* volatile curSplitPoint; @@ -106,7 +131,7 @@ class ThreadPool { public: void init(); // No c'tor, Threads object is global and engine shall be fully initialized - ~ThreadPool(); + ~ThreadPool(); Thread& operator[](size_t id) { return *threads[id]; } bool use_sleeping_threads() const { return useSleepingThreads; } @@ -131,8 +156,8 @@ private: std::vector threads; Thread* timer; - Lock splitLock; - WaitCondition sleepCond; + Mutex mutex; + ConditionVariable sleepCondition; Depth minimumSplitDepth; int maxThreadsPerSplitPoint; bool useSleepingThreads;