Пример #1
0
        // 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
        // point objects), 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.
        internal static Value split(bool Fake, Position pos, Stack[] ss, int ssPos, Value alpha, Value beta,
                                    Value bestValue, ref Move bestMove, Depth depth, Move threatMove,
                                    int moveCount, MovePicker mp, int nodeType)
        {
            Debug.Assert(pos.pos_is_ok());
            Debug.Assert(bestValue > -ValueC.VALUE_INFINITE);
            Debug.Assert(bestValue <= alpha);
            Debug.Assert(alpha < beta);
            Debug.Assert(beta <= ValueC.VALUE_INFINITE);
            Debug.Assert(depth > DepthC.DEPTH_ZERO);

            Thread master = pos.this_thread();

            if (master.splitPointsCnt >= Constants.MAX_SPLITPOINTS_PER_THREAD)
                return bestValue;

            // Pick the next available split point from the split point stack
            SplitPoint sp = master.splitPoints[master.splitPointsCnt];

            sp.parent = master.curSplitPoint;
            sp.master = master;
            sp.cutoff = false;
            sp.slavesMask = 1UL << master.idx;
#if ACTIVE_REPARENT
            sp.allSlavesRunning = true;
#endif

            sp.depth = depth;
            sp.bestMove = bestMove;
            sp.threatMove = threatMove;
            sp.alpha = alpha;
            sp.beta = beta;
            sp.nodeType = nodeType;
            sp.bestValue = bestValue;
            sp.mp = mp;
            sp.moveCount = moveCount;
            sp.pos = pos;
            sp.nodes = 0;
            sp.ss = ss;
            sp.ssPos = ssPos;

            Debug.Assert(master.is_searching);
            master.curSplitPoint = sp;

            int slavesCnt = 0;

            ThreadHelper.lock_grab(sp.Lock);
            ThreadHelper.lock_grab(splitLock);

            for (int i = 0; i < size() && !Fake; ++i)
                if (threads[i].is_available_to(master))
                {
                    sp.slavesMask |= 1UL << i;
                    threads[i].curSplitPoint = sp;
                    threads[i].is_searching = true; // Slave leaves idle_loop()

                    if (useSleepingThreads)
                        threads[i].wake_up();

                    if (++slavesCnt + 1 >= maxThreadsPerSplitPoint) // Master is always included
                        break;
                }

            master.splitPointsCnt++;

            ThreadHelper.lock_release(splitLock);
            ThreadHelper.lock_release(sp.Lock);

            // 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.
            // We pass the split point as a parameter to the idle loop, which means that
            // the thread will return from the idle loop when all slaves have finished
            // their work at this split point.
            if (slavesCnt != 0 || Fake)
            {
                master.idle_loop(sp, null);
                // In helpful master concept a master can help only a sub-tree of its split
                // point, and because here is all finished is not possible master is booked.
                Debug.Assert(!master.is_searching);
            }

            // We have returned from the idle loop, which means that all threads are
            // finished. Note that setting is_searching and decreasing activeSplitPoints is
            // done under lock protection to avoid a race with Thread::is_available_to().
            ThreadHelper.lock_grab(sp.Lock); // To protect sp->nodes
            ThreadHelper.lock_grab(splitLock);

            master.is_searching = true;
            master.splitPointsCnt--;
            master.curSplitPoint = sp.parent;
            pos.nodes += sp.nodes;
            bestMove = sp.bestMove;

            ThreadHelper.lock_release(splitLock);
            ThreadHelper.lock_release(sp.Lock);

            return sp.bestValue;
        }
Пример #2
0
        // 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.
        internal static void split(
            bool Fake,
            Position pos,
            Stack[] ss,
            int ssPos,
            int alpha,
            int beta,
            ref int bestValue,
            ref int bestMove,
            int depth,
            int threatMove,
            int moveCount,
            MovePicker movePicker,
            int nodeType)
        {
            Debug.Assert(bestValue <= alpha && alpha < beta && beta <= ValueC.VALUE_INFINITE);
            Debug.Assert(pos.pos_is_ok());
            Debug.Assert(bestValue > -ValueC.VALUE_INFINITE);
            Debug.Assert(depth > DepthC.DEPTH_ZERO);

            var thisThread = pos.this_thread();

            Debug.Assert(thisThread.searching);
            Debug.Assert(thisThread.splitPointsSize < Constants.MAX_SPLITPOINTS_PER_THREAD);

            // Pick the next available split point from the split point stack
            var sp = thisThread.splitPoints[thisThread.splitPointsSize];

            sp.parentSplitPoint = thisThread.activeSplitPoint;
            sp.master = thisThread;
            sp.cutoff = false;
            sp.slavesMask = 1UL << thisThread.idx;
#if ACTIVE_REPARENT
            sp.allSlavesRunning = true;
#endif

            sp.depth = depth;
            sp.bestMove = bestMove;
            sp.threatMove = threatMove;
            sp.alpha = alpha;
            sp.beta = beta;
            sp.nodeType = nodeType;
            sp.bestValue = bestValue;
            sp.movePicker = movePicker;
            sp.moveCount = moveCount;
            sp.pos = pos;
            sp.nodes = 0;
            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.
            ThreadHelper.lock_grab(splitLock);
            ThreadHelper.lock_grab(sp.Lock);

            thisThread.splitPointsSize++;
            thisThread.activeSplitPoint = sp;
            thisThread.activePosition = null;

            var slavesCnt = 1; // Master is always included
            Thread slave;
            while ((slave = Threads.available_slave(thisThread)) != null
                && ++slavesCnt <= Threads.maxThreadsPerSplitPoint && !Fake)
            {
                sp.slavesMask |= 1UL << slave.idx;
                slave.activeSplitPoint = sp;
                slave.searching = true; // Slave leaves idle_loop()

                slave.notify_one(); // Could be sleeping
            }

            ThreadHelper.lock_release(sp.Lock);
            ThreadHelper.lock_release(splitLock);

            // 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.
            // We pass the split point as a parameter to the idle loop, which means that
            // the thread will return from the idle loop when all slaves have finished
            // their work at this split point.
            if (slavesCnt > 1 || Fake)
            {
                thisThread.base_idle_loop(null); // Force a call to base class idle_loop()

                // In helpful master concept a master can help only a sub-tree of its split
                // point, and because here is all finished is not possible master is booked.
                Debug.Assert(!thisThread.searching);
                Debug.Assert(thisThread.activePosition == null);
            }

            // We have returned from the idle loop, which means that all threads are
            // finished. Note that setting searching and decreasing activeSplitPoints is
            // done under lock protection to avoid a race with Thread::is_available_to().
            ThreadHelper.lock_grab(splitLock);
            ThreadHelper.lock_grab(sp.Lock); // To protect sp->nodes

            thisThread.searching = true;
            thisThread.splitPointsSize--;
            thisThread.activeSplitPoint = sp.parentSplitPoint;
            thisThread.activePosition = pos;
            pos.nodes += sp.nodes;
            bestMove = sp.bestMove;
            bestValue = sp.bestValue;

            ThreadHelper.lock_release(sp.Lock);
            ThreadHelper.lock_release(splitLock);
        }