init_eval(ThreadsMgr.active_threads());
}
- // Wake up needed threads
- for (int i = 1; i < newActiveThreads; i++)
- ThreadsMgr.wake_sleeping_thread(i);
-
// Set thinking time
int myTime = time[pos.side_to_move()];
int myIncrement = increment[pos.side_to_move()];
if (UseLogFile)
LogFile.close();
- // This makes all the threads to go to sleep
- ThreadsMgr.set_active_threads(1);
-
return !Quit;
}
// Initialize a MovePicker object for the current position
// FIXME currently MovePicker() c'tor is needless called also in SplitPoint
- MovePicker mpBase = MovePicker(pos, ttMove, depth, H, ss, (PvNode ? -VALUE_INFINITE : beta));
+ MovePicker mpBase(pos, ttMove, depth, H, ss, (PvNode ? -VALUE_INFINITE : beta));
MovePicker& mp = SpNode ? *sp->mp : mpBase;
CheckInfo ci(pos);
ss->bestMove = MOVE_NONE;
newDepth = depth - ONE_PLY + ext;
// Update current move (this must be done after singular extension search)
- movesSearched[moveCount++] = ss->currentMove = move;
+ movesSearched[moveCount] = ss->currentMove = move;
+
+ if (!SpNode)
+ moveCount++;
// Step 12. Futility pruning (is omitted in PV nodes)
if ( !PvNode
if (value > bestValue && !(SpNode && ThreadsMgr.thread_should_stop(threadID)))
{
bestValue = value;
+
+ if (SpNode)
+ sp->bestValue = value;
+
if (value > alpha)
{
if (SpNode && (!PvNode || value >= beta))
sp->stopRequest = true;
if (PvNode && value < beta) // We want always alpha < beta
+ {
alpha = value;
+ if (SpNode)
+ sp->alpha = value;
+ }
if (value == value_mate_in(ply + 1))
ss->mateKiller = move;
ss->bestMove = move;
- }
- if (SpNode)
- {
- sp->bestValue = bestValue;
- sp->alpha = alpha;
- sp->parentSstack->bestMove = ss->bestMove;
+
+ if (SpNode)
+ sp->parentSstack->bestMove = move;
}
}
assert(threadID >= 0 && threadID < MAX_THREADS);
+ int i;
+ bool allFinished = false;
+
while (true)
{
// Slave threads can exit as soon as AllThreadsShouldExit raises,
// instead of wasting CPU time polling for work.
while ( threadID >= ActiveThreads
|| threads[threadID].state == THREAD_INITIALIZING
- || (!sp && threads[threadID].state == THREAD_AVAILABLE))
+ || threads[threadID].state == THREAD_AVAILABLE)
{
- assert(!sp);
- assert(threadID != 0);
-
- if (AllThreadsShouldExit)
- break;
-
lock_grab(&MPLock);
- // Retest condition under lock protection
- if (!( threadID >= ActiveThreads
- || threads[threadID].state == THREAD_INITIALIZING
- || (!sp && threads[threadID].state == THREAD_AVAILABLE)))
+ // Test with lock held to avoid races with wake_sleeping_thread()
+ for (i = 0; sp && i < ActiveThreads && !sp->slaves[i]; i++) {}
+ allFinished = (i == ActiveThreads);
+
+ // Retest sleep conditions under lock protection
+ if ( AllThreadsShouldExit
+ || allFinished
+ || !( threadID >= ActiveThreads
+ || threads[threadID].state == THREAD_INITIALIZING
+ || threads[threadID].state == THREAD_AVAILABLE))
{
lock_release(&MPLock);
- continue;
+ break;
}
// Put thread to sleep
if (tsp->pvNode)
search<PV, true>(pos, ss, tsp->alpha, tsp->beta, tsp->depth, tsp->ply);
- else
+ else {
search<NonPV, true>(pos, ss, tsp->alpha, tsp->beta, tsp->depth, tsp->ply);
-
+ }
assert(threads[threadID].state == THREAD_SEARCHING);
threads[threadID].state = THREAD_AVAILABLE;
+
+ // 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 (threadID != tsp->master && threads[tsp->master].state == THREAD_AVAILABLE)
+ wake_sleeping_thread(tsp->master);
}
// 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.
- int i = 0;
- for ( ; sp && i < ActiveThreads && !sp->slaves[i]; i++) {}
+ for (i = 0; sp && i < ActiveThreads && !sp->slaves[i]; i++) {}
+ allFinished = (i == ActiveThreads);
- if (i == ActiveThreads)
+ if (allFinished)
{
// Because sp->slaves[] is reset under lock protection,
// be sure sp->lock has been released before to return.
// 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 we tell our helper threads that they have
- // been assigned work. This will cause them to instantly leave their idle loops
- // and call sp_search(). When all threads have returned from sp_search() then
- // split() returns.
+ // 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.
template <bool Fake>
void ThreadsManager::split(const Position& p, SearchStack* ss, int ply, Value* alpha,
// Initialize the split point object
splitPoint.parent = masterThread.splitPoint;
+ splitPoint.master = master;
splitPoint.stopRequest = false;
splitPoint.ply = ply;
splitPoint.depth = depth;