]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Fix a race in idle_loop() exiting
[stockfish] / src / search.cpp
index 0c6cf8becbea5abd01e4918d2d3e4e60a317e6d4..7ba64c44337dbe3de43276342f89670d03ed64ba 100644 (file)
@@ -442,6 +442,10 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
   {
       ActiveThreads = newActiveThreads;
       init_eval(ActiveThreads);
+      // HACK: init_eval() destroys the static castleRightsMask[] array in the
+      // Position class. The below line repairs the damage.
+      Position p(pos.to_fen());
+      assert(pos.is_ok());
   }
 
   // Wake up sleeping threads
@@ -555,6 +559,7 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
 void init_threads() {
 
   volatile int i;
+  bool ok;
 
 #if !defined(_MSC_VER)
   pthread_t pthread[1];
@@ -594,12 +599,18 @@ void init_threads() {
   for (i = 1; i < THREAD_MAX; i++)
   {
 #if !defined(_MSC_VER)
-      pthread_create(pthread, NULL, init_thread, (void*)(&i));
+      ok = (pthread_create(pthread, NULL, init_thread, (void*)(&i)) == 0);
 #else
       DWORD iID[1];
-      CreateThread(NULL, 0, init_thread, (LPVOID)(&i), 0, iID);
+      ok = (CreateThread(NULL, 0, init_thread, (LPVOID)(&i), 0, iID) != NULL);
 #endif
 
+      if (!ok)
+      {
+          cout << "Failed to create thread number " << i << endl;
+          Application::exit_with_failure();
+      }
+
       // Wait until the thread has finished launching
       while (!Threads[i].running);
   }
@@ -830,7 +841,7 @@ namespace {
 
     // If we are pondering or in infinite search, we shouldn't print the
     // best move before we are told to do so.
-    if (!AbortSearch && (PonderSearch || InfiniteSearch))
+    if (!AbortSearch && !ExactMaxTime && (PonderSearch || InfiniteSearch))
         wait_for_stop_or_ponderhit();
     else
         // Print final search statistics
@@ -1802,7 +1813,7 @@ namespace {
     assert(threadID >= 0 && threadID < ActiveThreads);
     assert(ActiveThreads > 1);
 
-    Position pos = Position(sp->pos);
+    Position pos(*sp->pos);
     CheckInfo ci(pos);
     SearchStack* ss = sp->sstack[threadID];
     Value value = -VALUE_INFINITE;
@@ -1944,7 +1955,7 @@ namespace {
     assert(threadID >= 0 && threadID < ActiveThreads);
     assert(ActiveThreads > 1);
 
-    Position pos = Position(sp->pos);
+    Position pos(*sp->pos);
     CheckInfo ci(pos);
     SearchStack* ss = sp->sstack[threadID];
     Value value = -VALUE_INFINITE;
@@ -2009,7 +2020,14 @@ namespace {
               if (sp->ply == 1 && RootMoveNumber == 1)
                   Threads[threadID].failHighPly1 = true;
 
-              value = -search_pv(pos, ss, -sp->beta, -sp->alpha, newDepth, sp->ply+1, threadID);
+              // If another thread has failed high then sp->alpha has been increased
+              // to be higher or equal then beta, if so, avoid to start a PV search.
+              localAlpha = sp->alpha;
+              if (localAlpha < sp->beta)
+                  value = -search_pv(pos, ss, -sp->beta, -localAlpha, newDepth, sp->ply+1, threadID);
+              else
+                  assert(thread_should_stop(threadID));
+
               Threads[threadID].failHighPly1 = false;
         }
       }
@@ -2027,11 +2045,7 @@ namespace {
           sp->bestValue = value;
           if (value > sp->alpha)
           {
-              sp->alpha = value;
-              sp_update_pv(sp->parentSstack, ss, sp->ply);
-              if (value == value_mate_in(sp->ply + 1))
-                  ss[sp->ply].mateKiller = move;
-
+              // Ask threads to stop before to modify sp->alpha
               if (value >= sp->beta)
               {
                   for (int i = 0; i < ActiveThreads; i++)
@@ -2040,6 +2054,12 @@ namespace {
 
                   sp->finished = true;
               }
+
+              sp->alpha = value;
+
+              sp_update_pv(sp->parentSstack, ss, sp->ply);
+              if (value == value_mate_in(sp->ply + 1))
+                  ss[sp->ply].mateKiller = move;
         }
         // If we are at ply 1, and we are searching the first root move at
         // ply 0, set the 'Problem' variable if the score has dropped a lot
@@ -2783,6 +2803,8 @@ namespace {
       // If this thread has been assigned work, launch a search
       if (Threads[threadID].workIsWaiting)
       {
+          assert(!Threads[threadID].idle);
+
           Threads[threadID].workIsWaiting = false;
           if (Threads[threadID].splitPoint->pvNode)
               sp_search_pv(Threads[threadID].splitPoint, threadID);
@@ -2928,7 +2950,6 @@ namespace {
     assert(ActiveThreads > 1);
 
     SplitPoint* splitPoint;
-    int i;
 
     lock_grab(&MPLock);
 
@@ -2945,7 +2966,7 @@ namespace {
     splitPoint = SplitPointStack[master] + Threads[master].activeSplitPoints;
     Threads[master].activeSplitPoints++;
 
-    // Initialize the split point object and copy current position
+    // Initialize the split point object
     splitPoint->parent = Threads[master].splitPoint;
     splitPoint->finished = false;
     splitPoint->ply = ply;
@@ -2959,36 +2980,45 @@ namespace {
     splitPoint->mp = mp;
     splitPoint->moves = *moves;
     splitPoint->cpus = 1;
-    splitPoint->pos.copy(p);
+    splitPoint->pos = &p;
     splitPoint->parentSstack = sstck;
-    for (i = 0; i < ActiveThreads; i++)
+    for (int i = 0; i < ActiveThreads; i++)
         splitPoint->slaves[i] = 0;
 
-    // Copy the current search stack to the master thread
-    memcpy(splitPoint->sstack[master], sstck, (ply+1) * sizeof(SearchStack));
+    Threads[master].idle = false;
     Threads[master].splitPoint = splitPoint;
 
-    // Make copies of the current position and search stack for each thread
-    for (i = 0; i < ActiveThreads && splitPoint->cpus < MaxThreadsPerSplitPoint; i++)
+    // Allocate available threads setting idle flag to false
+    for (int i = 0; i < ActiveThreads && splitPoint->cpus < MaxThreadsPerSplitPoint; i++)
         if (thread_is_available(i, master))
         {
-            memcpy(splitPoint->sstack[i], sstck, (ply+1) * sizeof(SearchStack));
+            Threads[i].idle = false;
             Threads[i].splitPoint = splitPoint;
             splitPoint->slaves[i] = 1;
             splitPoint->cpus++;
         }
 
+    assert(splitPoint->cpus > 1);
+
+    // We can release the lock because master and slave threads are already booked
+    lock_release(&MPLock);
+
+    // Copy the tail of current search stack to the master thread
+    memcpy(splitPoint->sstack[master] + ply - 1, sstck + ply - 1, 3 * sizeof(SearchStack));
+
     // Tell the threads that they have work to do. This will make them leave
-    // their idle loop.
-    for (i = 0; i < ActiveThreads; i++)
+    // their idle loop. Also copy search stack tail for each slave thread.
+    for (int i = 0; i < ActiveThreads; i++)
+    {
+        if (splitPoint->slaves[i])
+            memcpy(splitPoint->sstack[i] + ply - 1, sstck + ply - 1, 3 * sizeof(SearchStack));
+
         if (i == master || splitPoint->slaves[i])
         {
-            Threads[i].workIsWaiting = true;
-            Threads[i].idle = false;
             Threads[i].stop = false;
+            Threads[i].workIsWaiting = true; // This makes the slave to exit from idle_loop()
         }
-
-    lock_release(&MPLock);
+    }
 
     // Everything is set up. The master thread enters the idle loop, from
     // which it will instantly launch a search, because its workIsWaiting