// cutoff_occurred() checks whether a beta cutoff has occurred in the // current active split point, or in some ancestor of the split point. public bool cutoff_occurred() { for (SplitPoint sp = activeSplitPoint; sp != null; sp = sp.parentSplitPoint) if (sp.cutoff) return true; return false; }
public Thread(): base(){ searching = exit = false; maxPly = splitPointsSize = 0; activeSplitPoint = null; activePosition = null; idx = Engine.Threads.Count; for (int i = 0; i < MAX_SPLITPOINTS_PER_THREAD; i++) splitPoints[i] = new SplitPoint(); }
// 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), the function immediately returns. // If splitting is possible, a SplitPoint object is initialized with all the // data that must be copied to the helper threads and then helper threads are // told that they have been assigned work. This will cause them to instantly // leave their idle loops and call search(). When all threads have returned from // search() then split() returns. public void split(Position pos, Stack[] ss, int ssPos, Value alpha, Value beta, ref Value bestValue, ref Move bestMove, Depth depth, int moveCount, MovePicker movePicker, int nodeType, bool cutNode, bool Fake) { Debug.Assert(pos.pos_is_ok()); Debug.Assert(-ValueS.VALUE_INFINITE < bestValue && bestValue <= alpha && alpha < beta && beta <= ValueS.VALUE_INFINITE); Debug.Assert(depth >= Engine.Threads.minimumSplitDepth); Debug.Assert(searching); Debug.Assert(splitPointsSize < MAX_SPLITPOINTS_PER_THREAD); // Pick the next available split point from the split point stack SplitPoint sp = splitPoints[splitPointsSize]; sp.masterThread = this; sp.parentSplitPoint = activeSplitPoint; sp.slavesMask.SetAll(false); sp.slavesMask[idx] = true; sp.depth = depth; sp.bestValue = bestValue; sp.bestMove = bestMove; sp.alpha = alpha; sp.beta = beta; sp.nodeType = nodeType; sp.cutNode = cutNode; sp.movePicker = movePicker; sp.moveCount = moveCount; sp.pos = pos; sp.nodes = 0; sp.cutoff = false; sp.ss = ss; sp.ssPos = ssPos; // Try to allocate available threads and ask them to start searching setting // 'searching' flag. This must be done under lock protection to avoid concurrent // allocation of the same slave by another master. Engine.Threads.mutex.Lock(); sp.mutex.Lock(); sp.allSlavesSearching = true; // Must be set under lock protection ++splitPointsSize; activeSplitPoint = sp; activePosition = null; if (!Fake) for (Thread slave; (slave = Engine.Threads.available_slave(this)) != null; ) { sp.slavesMask[slave.idx] = true; slave.activeSplitPoint = sp; slave.searching = true; // Slave leaves idle_loop() slave.notify_one(); // Could be sleeping } // Everything is set up. The master thread enters the idle loop, from which // it will instantly launch a search, because its 'searching' flag is set. // The thread will return from the idle loop when all slaves have finished // their work at this split point. sp.mutex.UnLock(); Engine.Threads.mutex.UnLock(); idle_loop_base(); // Force a call to base class idle_loop()//TODO, si se llama a la base?? // In the helpful master concept, a master can help only a sub-tree of its // split point and because everything is finished here, it's not possible // for the master to be booked. Debug.Assert(!searching); Debug.Assert(activePosition == null); // We have returned from the idle loop, which means that all threads are // finished. Note that setting 'searching' and decreasing splitPointsSize is // done under lock protection to avoid a race with Thread::available_to(). Engine.Threads.mutex.Lock(); sp.mutex.Lock(); searching = true; --splitPointsSize; activeSplitPoint = sp.parentSplitPoint; activePosition = pos; pos.set_nodes_searched(pos.nodes_searched() + sp.nodes); bestMove = sp.bestMove; bestValue = sp.bestValue; sp.mutex.UnLock(); Engine.Threads.mutex.UnLock(); }