]> git.sesse.net Git - stockfish/blobdiff - src/thread.cpp
When exiting wake up all threads at once
[stockfish] / src / thread.cpp
index f620c71c69d2640de29e098ba904f68ddcadd023..d845fdf2e4183f2fdaa10bb656b66d1ab6439749 100644 (file)
@@ -84,7 +84,7 @@ bool Thread::cutoff_occurred() const {
 
 bool Thread::is_available_to(int master) const {
 
-  if (state != AVAILABLE)
+  if (is_searching)
       return false;
 
   // Make a local copy to be sure doesn't become zero under our feet while
@@ -161,7 +161,7 @@ void ThreadsManager::init() {
   }
 
   // Initialize main thread's associated data
-  threads[0].state = Thread::SEARCHING;
+  threads[0].is_searching = true;
   threads[0].threadID = 0;
   set_size(1); // This makes all the threads but the main to go to sleep
 
@@ -169,7 +169,7 @@ void ThreadsManager::init() {
   // threads will go immediately to sleep.
   for (int i = 1; i < MAX_THREADS; i++)
   {
-      threads[i].state = Thread::AVAILABLE;
+      threads[i].is_searching = false;
       threads[i].threadID = i;
 
 #if defined(_MSC_VER)
@@ -192,14 +192,19 @@ void ThreadsManager::init() {
 
 void ThreadsManager::exit() {
 
+  // Wake up all the slave threads at once. This is faster than "wake and wait"
+  // for each thread and avoids a rare crash once every 10K games under Linux.
+  for (int i = 1; i < MAX_THREADS; i++)
+  {
+      threads[i].do_terminate = true;
+      threads[i].wake_up();
+  }
+
   for (int i = 0; i < MAX_THREADS; i++)
   {
-      // Wake up all the slave threads and wait for termination
       if (i != 0)
       {
-          threads[i].do_terminate = true;
-          threads[i].wake_up();
-
+          // Wait for slave termination
 #if defined(_MSC_VER)
           WaitForSingleObject(threads[i].handle, 0);
           CloseHandle(threads[i].handle);
@@ -286,7 +291,7 @@ Value ThreadsManager::split(Position& pos, SearchStack* ss, Value alpha, Value b
       sp->is_slave[i] = false;
 
   // If we are here it means we are not available
-  assert(masterThread.state == Thread::SEARCHING);
+  assert(masterThread.is_searching);
 
   int workersCnt = 1; // At least the master is included
 
@@ -303,7 +308,7 @@ Value ThreadsManager::split(Position& pos, SearchStack* ss, Value alpha, Value b
           threads[i].splitPoint = sp;
 
           // This makes the slave to exit from idle_loop()
-          threads[i].state = Thread::SEARCHING;
+          threads[i].is_searching = true;
 
           if (useSleepingThreads)
               threads[i].wake_up();
@@ -318,23 +323,23 @@ Value ThreadsManager::split(Position& pos, SearchStack* ss, Value alpha, Value b
   masterThread.splitPoint = sp;
   masterThread.activeSplitPoints++;
 
-  // Everything is set up. The master thread enters the idle loop, from
-  // which it will instantly launch a search, because its state is
-  // Thread::WORKISWAITING. We send the split point as a second parameter to
-  // the idle loop, which means that the main thread will return from the idle
-  // loop when all threads have finished their work at this split point.
+  // 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.
   masterThread.idle_loop(sp);
 
   // In helpful master concept a master can help only a sub-tree, and
   // because here is all finished is not possible master is booked.
-  assert(masterThread.state == Thread::AVAILABLE);
+  assert(!masterThread.is_searching);
 
   // We have returned from the idle loop, which means that all threads are
   // finished. Note that changing state and decreasing activeSplitPoints is done
   // under lock protection to avoid a race with Thread::is_available_to().
   lock_grab(&threadsLock);
 
-  masterThread.state = Thread::SEARCHING;
+  masterThread.is_searching = true;
   masterThread.activeSplitPoints--;
 
   lock_release(&threadsLock);