// ThreadsManager::wait_for_search_finished() waits for main thread to go to // sleep, this means search is finished. Then returns. internal static void wait_for_search_finished() { Thread t = main_thread(); ThreadHelper.lock_grab(t.sleepLock); ThreadHelper.cond_signal(t.sleepCond); // In case is waiting for stop or ponderhit while (!t.do_sleep) { ThreadHelper.cond_wait(sleepCond, t.sleepLock); } ThreadHelper.lock_release(t.sleepLock); }
internal void wait_for_stop_or_ponderhit() { Search.SignalsStopOnPonderhit = true; ThreadHelper.lock_grab(sleepLock); while (!Search.SignalsStop) { ThreadHelper.cond_wait(sleepCond, sleepLock); } ThreadHelper.lock_release(sleepLock); }
// Thread::main_loop() is where the main thread is parked waiting to be started // when there is a new search. Main thread will launch all the slave threads. internal void main_loop(ManualResetEvent initEvent) { // Initialize the TT here UInt32 ttSize = UInt32.Parse(OptionMap.Instance["Hash"].v); if (TT.size != ttSize) { TT.set_size(ttSize); } // Signal done initEvent.Set(); while (true) { ThreadHelper.lock_grab(sleepLock); do_sleep = true; // Always return to sleep after a search is_searching = false; while (do_sleep && !do_exit) { ThreadHelper.cond_signal(Threads.sleepCond); // Wake up UI thread if needed ThreadHelper.cond_wait(sleepCond, sleepLock); } ThreadHelper.lock_release(sleepLock); if (do_exit) { return; } is_searching = true; Search.think(); // This is the search entry point } }
/// Thread::idle_loop() is where the thread is parked when it has no work to do. /// The parameter 'master_sp', if non-NULL, is a pointer to an active SplitPoint /// object for which the thread is the master. internal void idle_loop(SplitPoint sp_master, ManualResetEvent initEvent) { if (initEvent != null) { // Signal done initEvent.Set(); } bool use_sleeping_threads = Threads.useSleepingThreads; // If this thread is the master of a split point and all slaves have // finished their work at this split point, return from the idle loop. while ((sp_master == null) || (sp_master.slavesMask != 0)) { // If we are not searching, wait for a condition to be signaled // instead of wasting CPU time polling for work. while (do_sleep || do_exit || (!is_searching && use_sleeping_threads)) { if (do_exit) { Debug.Assert(sp_master == null); return; } // Grab the lock to avoid races with Thread::wake_up() ThreadHelper.lock_grab(sleepLock); // If we are master and all slaves have finished don't go to sleep if ((sp_master != null) && (sp_master.slavesMask == 0)) { ThreadHelper.lock_release(sleepLock); break; } // Do sleep after retesting sleep conditions under lock protection, in // particular we need to avoid a deadlock in case a master thread has, // 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) { ThreadHelper.cond_wait(sleepCond, sleepLock); } ThreadHelper.lock_release(sleepLock); } // If this thread has been assigned work, launch a search if (is_searching) { Debug.Assert(!do_sleep && !do_exit); ThreadHelper.lock_grab(Threads.splitLock); Debug.Assert(is_searching); SplitPoint sp = curSplitPoint; ThreadHelper.lock_release(Threads.splitLock); LoopStack ls = LoopStackBroker.GetObject(); Stack[] ss = ls.ss; int ssPos = 0; Position pos = PositionBroker.GetObject(); pos.copy(sp.pos, this); Array.Copy(sp.ss, sp.ssPos - 1, ss, ssPos, 4); ss[ssPos + 1].sp = sp; ThreadHelper.lock_grab(sp.Lock); if (sp.nodeType == NodeTypeC.Root) { Search.search(NodeTypeC.SplitPointRoot, pos, ss, ssPos + 1, sp.alpha, sp.beta, sp.depth); } else if (sp.nodeType == NodeTypeC.PV) { Search.search(NodeTypeC.SplitPointPV, pos, ss, ssPos + 1, sp.alpha, sp.beta, sp.depth); } else if (sp.nodeType == NodeTypeC.NonPV) { Search.search(NodeTypeC.SplitPointNonPV, pos, ss, ssPos + 1, sp.alpha, sp.beta, sp.depth); } else { Debug.Assert(false); } Debug.Assert(is_searching); is_searching = false; #if ACTIVE_REPARENT sp.allSlavesRunning = false; #endif sp.slavesMask &= ~(1UL << idx); sp.nodes += pos.nodes; // Wake up master thread so to allow it to return from the idle loop in // case we are the last slave of the split point. if (use_sleeping_threads && this != sp.master && !sp.master.is_searching) { sp.master.wake_up(); } // After releasing the lock we cannot access anymore any SplitPoint // 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. ThreadHelper.lock_release(sp.Lock); #if ACTIVE_REPARENT // Try to reparent to the first split point, with still all slaves // running, where we are available as a possible slave. for (int i = 0; i < Threads.size(); i++) { Thread th = Threads.threads[i]; int spCnt = th.splitPointsCnt; SplitPoint latest = th.splitPoints[spCnt != 0 ? spCnt - 1 : 0]; if (this.is_available_to(th) && spCnt > 0 && !th.cutoff_occurred() && latest.allSlavesRunning && Utils.more_than_one(latest.slavesMask)) { ThreadHelper.lock_grab(latest.Lock); ThreadHelper.lock_grab(Threads.splitLock); // Retest all under lock protection, we are in the middle // of a race storm here ! if (this.is_available_to(th) && spCnt == th.splitPointsCnt && !th.cutoff_occurred() && latest.allSlavesRunning && Utils.more_than_one(latest.slavesMask)) { latest.slavesMask |= 1UL << idx; curSplitPoint = latest; is_searching = true; } ThreadHelper.lock_release(Threads.splitLock); ThreadHelper.lock_release(latest.Lock); break; // Exit anyhow, only one try (enough in 99% of cases) } } #endif pos.startState = null; pos.st = null; PositionBroker.Free(); LoopStackBroker.Free(ls); } } }