internal Thread(ThreadLoopType lt, ManualResetEvent initEvent) { is_searching = do_exit = false; maxPly = splitPointsCnt = 0; curSplitPoint = null; loopType = lt; idx = Threads.size(); do_sleep = loopType != ThreadLoopType.Main; // Avoid a race with start_searching() for (int j = 0; j < Constants.MAX_SPLITPOINTS_PER_THREAD; j++) { splitPoints[j] = new SplitPoint(); } #if WINDOWS_RT Windows.Foundation.IAsyncAction action = Windows.System.Threading.ThreadPool.RunAsync(delegate { StartThread(initEvent); }, WorkItemPriority.Normal); #else ThreadPool.QueueUserWorkItem(this.StartThread, initEvent); #endif }
/// 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); } } }