]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Move the last multi-threads globals to ThreadsManager
[stockfish] / src / search.cpp
index c5c8b839db343d9ec4396e2f74d759965465aa4c..b6493837981ca5394a6101f06c372b7479aa4369 100644 (file)
@@ -59,6 +59,10 @@ namespace {
   // Used for debugging SMP code.
   const bool FakeSplit = false;
 
+  // Fast lookup table of sliding pieces indexed by Piece
+  const bool Slidings[18] = { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1 };
+  inline bool piece_is_slider(Piece p) { return Slidings[p]; }
+
   // ThreadsManager class is used to handle all the threads related stuff in search,
   // init, starting, parking and, the most important, launching a slave thread at a
   // split point are what this class does. All the access to shared thread data is
@@ -73,9 +77,11 @@ namespace {
     void init_threads();
     void exit_threads();
 
-    int active_threads() const { return ActiveThreads; }
-    void set_active_threads(int newActiveThreads) { ActiveThreads = newActiveThreads; }
+    int min_split_depth() const { return minimumSplitDepth; }
+    int active_threads() const { return activeThreads; }
+    void set_active_threads(int cnt) { activeThreads = cnt; }
 
+    void read_uci_options();
     bool available_thread_exists(int master) const;
     bool thread_is_available(int slave, int master) const;
     bool thread_should_stop(int threadID) const;
@@ -87,11 +93,14 @@ namespace {
                Depth depth, Move threatMove, bool mateThreat, int moveCount, MovePicker* mp, bool pvNode);
 
   private:
-    int ActiveThreads;
-    volatile bool AllThreadsShouldExit;
+    Depth minimumSplitDepth;
+    int maxThreadsPerSplitPoint;
+    bool useSleepingThreads;
+    int activeThreads;
+    volatile bool allThreadsShouldExit;
     Thread threads[MAX_THREADS];
-    Lock MPLock;
-    WaitCondition WaitCond[MAX_THREADS];
+    Lock mpLock, sleepLock[MAX_THREADS];
+    WaitCondition sleepCond[MAX_THREADS];
   };
 
 
@@ -228,7 +237,10 @@ namespace {
   const Value EasyMoveMargin = Value(0x200);
 
 
-  /// Global variables
+  /// Namespace variables
+
+  // Book object
+  Book OpeningBook;
 
   // Iteration counter
   int Iteration;
@@ -253,9 +265,7 @@ namespace {
   bool UseLogFile;
   std::ofstream LogFile;
 
-  // Multi-threads related variables
-  Depth MinimumSplitDepth;
-  int MaxThreadsPerSplitPoint;
+  // Multi-threads manager object
   ThreadsManager ThreadsMgr;
 
   // Node counters, used only by thread[0] but try to keep in different cache
@@ -340,7 +350,7 @@ void init_search() {
   // Init reductions array
   for (hd = 1; hd < 64; hd++) for (mc = 1; mc < 64; mc++)
   {
-      double    pvRed = 0.33 + log(double(hd)) * log(double(mc)) / 4.5;
+      double    pvRed = log(double(hd)) * log(double(mc)) / 3.0;
       double nonPVRed = 0.33 + log(double(hd)) * log(double(mc)) / 2.25;
       ReductionMatrix[PV][hd][mc]    = (int8_t) (   pvRed >= 1.0 ? floor(   pvRed * int(ONE_PLY)) : 0);
       ReductionMatrix[NonPV][hd][mc] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(ONE_PLY)) : 0);
@@ -407,12 +417,12 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
   UseTimeManagement = !ExactMaxTime && !MaxDepth && !MaxNodes && !InfiniteSearch;
 
   // Look for a book move, only during games, not tests
-  if (UseTimeManagement && get_option_value_bool("OwnBook"))
+  if (UseTimeManagement && Options["OwnBook"].value<bool>())
   {
-      if (get_option_value_string("Book File") != OpeningBook.file_name())
-          OpeningBook.open(get_option_value_string("Book File"));
+      if (Options["Book File"].value<std::string>() != OpeningBook.file_name())
+          OpeningBook.open(Options["Book File"].value<std::string>());
 
-      Move bookMove = OpeningBook.get_move(pos, get_option_value_bool("Best Book Move"));
+      Move bookMove = OpeningBook.get_move(pos, Options["Best Book Move"].value<bool>());
       if (bookMove != MOVE_NONE)
       {
           if (PonderSearch)
@@ -424,43 +434,40 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
   }
 
   // Read UCI option values
-  TT.set_size(get_option_value_int("Hash"));
-  if (get_option_value_bool("Clear Hash"))
+  TT.set_size(Options["Hash"].value<int>());
+  if (Options["Clear Hash"].value<bool>())
   {
-      set_option_value("Clear Hash", "false");
+      Options["Clear Hash"].set_value("false");
       TT.clear();
   }
 
-  CheckExtension[1]         = Depth(get_option_value_int("Check Extension (PV nodes)"));
-  CheckExtension[0]         = Depth(get_option_value_int("Check Extension (non-PV nodes)"));
-  SingleEvasionExtension[1] = Depth(get_option_value_int("Single Evasion Extension (PV nodes)"));
-  SingleEvasionExtension[0] = Depth(get_option_value_int("Single Evasion Extension (non-PV nodes)"));
-  PawnPushTo7thExtension[1] = Depth(get_option_value_int("Pawn Push to 7th Extension (PV nodes)"));
-  PawnPushTo7thExtension[0] = Depth(get_option_value_int("Pawn Push to 7th Extension (non-PV nodes)"));
-  PassedPawnExtension[1]    = Depth(get_option_value_int("Passed Pawn Extension (PV nodes)"));
-  PassedPawnExtension[0]    = Depth(get_option_value_int("Passed Pawn Extension (non-PV nodes)"));
-  PawnEndgameExtension[1]   = Depth(get_option_value_int("Pawn Endgame Extension (PV nodes)"));
-  PawnEndgameExtension[0]   = Depth(get_option_value_int("Pawn Endgame Extension (non-PV nodes)"));
-  MateThreatExtension[1]    = Depth(get_option_value_int("Mate Threat Extension (PV nodes)"));
-  MateThreatExtension[0]    = Depth(get_option_value_int("Mate Threat Extension (non-PV nodes)"));
-
-  MinimumSplitDepth       = get_option_value_int("Minimum Split Depth") * ONE_PLY;
-  MaxThreadsPerSplitPoint = get_option_value_int("Maximum Number of Threads per Split Point");
-  MultiPV                 = get_option_value_int("MultiPV");
-  UseLogFile              = get_option_value_bool("Use Search Log");
+  CheckExtension[1]         = Options["Check Extension (PV nodes)"].value<Depth>();
+  CheckExtension[0]         = Options["Check Extension (non-PV nodes)"].value<Depth>();
+  SingleEvasionExtension[1] = Options["Single Evasion Extension (PV nodes)"].value<Depth>();
+  SingleEvasionExtension[0] = Options["Single Evasion Extension (non-PV nodes)"].value<Depth>();
+  PawnPushTo7thExtension[1] = Options["Pawn Push to 7th Extension (PV nodes)"].value<Depth>();
+  PawnPushTo7thExtension[0] = Options["Pawn Push to 7th Extension (non-PV nodes)"].value<Depth>();
+  PassedPawnExtension[1]    = Options["Passed Pawn Extension (PV nodes)"].value<Depth>();
+  PassedPawnExtension[0]    = Options["Passed Pawn Extension (non-PV nodes)"].value<Depth>();
+  PawnEndgameExtension[1]   = Options["Pawn Endgame Extension (PV nodes)"].value<Depth>();
+  PawnEndgameExtension[0]   = Options["Pawn Endgame Extension (non-PV nodes)"].value<Depth>();
+  MateThreatExtension[1]    = Options["Mate Threat Extension (PV nodes)"].value<Depth>();
+  MateThreatExtension[0]    = Options["Mate Threat Extension (non-PV nodes)"].value<Depth>();
+  MultiPV                   = Options["MultiPV"].value<int>();
+  UseLogFile                = Options["Use Search Log"].value<bool>();
 
   if (UseLogFile)
-      LogFile.open(get_option_value_string("Search Log Filename").c_str(), std::ios::out | std::ios::app);
+      LogFile.open(Options["Search Log Filename"].value<std::string>().c_str(), std::ios::out | std::ios::app);
 
   read_weights(pos.side_to_move());
 
   // Set the number of active threads
-  int newActiveThreads = get_option_value_int("Threads");
-  if (newActiveThreads != ThreadsMgr.active_threads())
-  {
-      ThreadsMgr.set_active_threads(newActiveThreads);
-      init_eval(ThreadsMgr.active_threads());
-  }
+  ThreadsMgr.read_uci_options();
+  init_eval(ThreadsMgr.active_threads());
+
+  // Wake up needed threads
+  for (int i = 1; i < ThreadsMgr.active_threads(); i++)
+      ThreadsMgr.wake_sleeping_thread(i);
 
   // Set thinking time
   int myTime = time[pos.side_to_move()];
@@ -494,6 +501,9 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
   if (UseLogFile)
       LogFile.close();
 
+  // This makes all the threads to go to sleep
+  ThreadsMgr.set_active_threads(1);
+
   return !Quit;
 }
 
@@ -647,7 +657,7 @@ namespace {
              << " time " << current_search_time() << endl;
 
     // Print the best move and the ponder move to the standard output
-    if (pv[0] == MOVE_NONE)
+    if (pv[0] == MOVE_NONE || MultiPV > 1)
     {
         pv[0] = rml.move(0);
         pv[1] = MOVE_NONE;
@@ -1056,7 +1066,6 @@ namespace {
         && !isCheck
         &&  refinedValue < beta - razor_margin(depth)
         &&  ttMove == MOVE_NONE
-        &&  (ss-1)->currentMove != MOVE_NULL
         && !value_is_mate(beta)
         && !pos.has_pawn_on_7th(pos.side_to_move()))
     {
@@ -1273,6 +1282,17 @@ split_point_start: // At split points actual search starts from here
 
               continue;
           }
+
+          // Prune neg. see moves at low depths
+          if (   predictedDepth < 2 * ONE_PLY
+              && bestValue > value_mated_in(PLY_MAX)
+              && pos.see_sign(move) < 0)
+          {
+              if (SpNode)
+                  lock_grab(&(sp->lock));
+
+              continue;
+          }
       }
 
       // Step 13. Make the move
@@ -1377,7 +1397,7 @@ split_point_start: // At split points actual search starts from here
 
       // Step 18. Check for split
       if (   !SpNode
-          && depth >= MinimumSplitDepth
+          && depth >= ThreadsMgr.min_split_depth()
           && ThreadsMgr.active_threads() > 1
           && bestValue < beta
           && ThreadsMgr.available_thread_exists(threadID)
@@ -1927,7 +1947,7 @@ split_point_start: // At split points actual search starts from here
     int t = current_search_time();
 
     //  Poll for input
-    if (Bioskey())
+    if (data_available())
     {
         // We are line oriented, don't read single chars
         std::string command;
@@ -2167,6 +2187,19 @@ split_point_start: // At split points actual search starts from here
   /// The ThreadsManager class
 
 
+  // read_uci_options() updates number of active threads and other internal
+  // parameters according to the UCI options values. It is called before
+  // to start a new search.
+
+  void ThreadsManager::read_uci_options() {
+
+    maxThreadsPerSplitPoint = Options["Maximum Number of Threads per Split Point"].value<int>();
+    minimumSplitDepth       = Options["Minimum Split Depth"].value<int>() * ONE_PLY;
+    useSleepingThreads      = Options["Use Sleeping Threads"].value<bool>();
+    activeThreads           = Options["Threads"].value<int>();
+  }
+
+
   // idle_loop() is where the threads are parked when they have no work to do.
   // The parameter 'sp', if non-NULL, is a pointer to an active SplitPoint
   // object for which the current thread is the master.
@@ -2175,11 +2208,14 @@ split_point_start: // At split points actual search starts from here
 
     assert(threadID >= 0 && threadID < MAX_THREADS);
 
+    int i;
+    bool allFinished = false;
+
     while (true)
     {
         // Slave threads can exit as soon as AllThreadsShouldExit raises,
         // master should exit as last one.
-        if (AllThreadsShouldExit)
+        if (allThreadsShouldExit)
         {
             assert(!sp);
             threads[threadID].state = THREAD_TERMINATED;
@@ -2188,37 +2224,39 @@ split_point_start: // At split points actual search starts from here
 
         // If we are not thinking, wait for a condition to be signaled
         // instead of wasting CPU time polling for work.
-        while (   threadID >= ActiveThreads
-               || threads[threadID].state == THREAD_INITIALIZING
-               || (!sp && threads[threadID].state == THREAD_AVAILABLE))
+        while (   threadID >= activeThreads || threads[threadID].state == THREAD_INITIALIZING
+               || (useSleepingThreads && threads[threadID].state == THREAD_AVAILABLE))
         {
-            assert(!sp);
-            assert(threadID != 0);
+            assert(!sp || useSleepingThreads);
+            assert(threadID != 0 || useSleepingThreads);
 
-            if (AllThreadsShouldExit)
-                break;
+            if (threads[threadID].state == THREAD_INITIALIZING)
+                threads[threadID].state = THREAD_AVAILABLE;
+
+            // Grab the lock to avoid races with wake_sleeping_thread()
+            lock_grab(&sleepLock[threadID]);
 
-            lock_grab(&MPLock);
+            // If we are master and all slaves have finished do not go to sleep
+            for (i = 0; sp && i < activeThreads && !sp->slaves[i]; i++) {}
+            allFinished = (i == activeThreads);
 
-            // Retest condition under lock protection
-            if (!(   threadID >= ActiveThreads
-                  || threads[threadID].state == THREAD_INITIALIZING
-                  || (!sp && threads[threadID].state == THREAD_AVAILABLE)))
+            if (allFinished || allThreadsShouldExit)
             {
-                lock_release(&MPLock);
-                continue;
+                lock_release(&sleepLock[threadID]);
+                break;
             }
 
-            // Put thread to sleep
-            threads[threadID].state = THREAD_AVAILABLE;
-            cond_wait(&WaitCond[threadID], &MPLock);
-            lock_release(&MPLock);
+            // Do sleep here after retesting sleep conditions
+            if (threadID >= activeThreads || threads[threadID].state == THREAD_AVAILABLE)
+                cond_wait(&sleepCond[threadID], &sleepLock[threadID]);
+
+            lock_release(&sleepLock[threadID]);
         }
 
         // If this thread has been assigned work, launch a search
         if (threads[threadID].state == THREAD_WORKISWAITING)
         {
-            assert(!AllThreadsShouldExit);
+            assert(!allThreadsShouldExit);
 
             threads[threadID].state = THREAD_SEARCHING;
 
@@ -2230,20 +2268,25 @@ split_point_start: // At split points actual search starts from here
 
             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 (useSleepingThreads && 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.
@@ -2271,10 +2314,13 @@ split_point_start: // At split points actual search starts from here
     bool ok;
 
     // Initialize global locks
-    lock_init(&MPLock);
+    lock_init(&mpLock);
 
     for (i = 0; i < MAX_THREADS; i++)
-        cond_init(&WaitCond[i]);
+    {
+        lock_init(&sleepLock[i]);
+        cond_init(&sleepCond[i]);
+    }
 
     // Initialize splitPoints[] locks
     for (i = 0; i < MAX_THREADS; i++)
@@ -2282,10 +2328,10 @@ split_point_start: // At split points actual search starts from here
             lock_init(&(threads[i].splitPoints[j].lock));
 
     // Will be set just before program exits to properly end the threads
-    AllThreadsShouldExit = false;
+    allThreadsShouldExit = false;
 
     // Threads will be put all threads to sleep as soon as created
-    ActiveThreads = 1;
+    activeThreads = 1;
 
     // All threads except the main thread should be initialized to THREAD_INITIALIZING
     threads[0].state = THREAD_SEARCHING;
@@ -2307,7 +2353,7 @@ split_point_start: // At split points actual search starts from here
         if (!ok)
         {
             cout << "Failed to create thread number " << i << endl;
-            Application::exit_with_failure();
+            exit(EXIT_FAILURE);
         }
 
         // Wait until the thread has finished launching and is gone to sleep
@@ -2321,7 +2367,7 @@ split_point_start: // At split points actual search starts from here
 
   void ThreadsManager::exit_threads() {
 
-    AllThreadsShouldExit = true; // Let the woken up threads to exit idle_loop()
+    allThreadsShouldExit = true; // Let the woken up threads to exit idle_loop()
 
     // Wake up all the threads and waits for termination
     for (int i = 1; i < MAX_THREADS; i++)
@@ -2335,11 +2381,14 @@ split_point_start: // At split points actual search starts from here
         for (int j = 0; j < MAX_ACTIVE_SPLIT_POINTS; j++)
             lock_destroy(&(threads[i].splitPoints[j].lock));
 
-    lock_destroy(&MPLock);
+    lock_destroy(&mpLock);
 
     // Now we can safely destroy the wait conditions
     for (int i = 0; i < MAX_THREADS; i++)
-        cond_destroy(&WaitCond[i]);
+    {
+        lock_destroy(&sleepLock[i]);
+        cond_destroy(&sleepCond[i]);
+    }
   }
 
 
@@ -2349,7 +2398,7 @@ split_point_start: // At split points actual search starts from here
 
   bool ThreadsManager::thread_should_stop(int threadID) const {
 
-    assert(threadID >= 0 && threadID < ActiveThreads);
+    assert(threadID >= 0 && threadID < activeThreads);
 
     SplitPoint* sp = threads[threadID].splitPoint;
 
@@ -2368,9 +2417,9 @@ split_point_start: // At split points actual search starts from here
 
   bool ThreadsManager::thread_is_available(int slave, int master) const {
 
-    assert(slave >= 0 && slave < ActiveThreads);
-    assert(master >= 0 && master < ActiveThreads);
-    assert(ActiveThreads > 1);
+    assert(slave >= 0 && slave < activeThreads);
+    assert(master >= 0 && master < activeThreads);
+    assert(activeThreads > 1);
 
     if (threads[slave].state != THREAD_AVAILABLE || slave == master)
         return false;
@@ -2380,7 +2429,7 @@ split_point_start: // At split points actual search starts from here
 
     // No active split points means that the thread is available as
     // a slave for any other thread.
-    if (localActiveSplitPoints == 0 || ActiveThreads == 2)
+    if (localActiveSplitPoints == 0 || activeThreads == 2)
         return true;
 
     // Apply the "helpful master" concept if possible. Use localActiveSplitPoints
@@ -2398,10 +2447,10 @@ split_point_start: // At split points actual search starts from here
 
   bool ThreadsManager::available_thread_exists(int master) const {
 
-    assert(master >= 0 && master < ActiveThreads);
-    assert(ActiveThreads > 1);
+    assert(master >= 0 && master < activeThreads);
+    assert(activeThreads > 1);
 
-    for (int i = 0; i < ActiveThreads; i++)
+    for (int i = 0; i < activeThreads; i++)
         if (thread_is_available(i, master))
             return true;
 
@@ -2429,20 +2478,20 @@ split_point_start: // At split points actual search starts from here
     assert(*alpha < beta);
     assert(beta <= VALUE_INFINITE);
     assert(depth > DEPTH_ZERO);
-    assert(pos.thread() >= 0 && pos.thread() < ActiveThreads);
-    assert(ActiveThreads > 1);
+    assert(pos.thread() >= 0 && pos.thread() < activeThreads);
+    assert(activeThreads > 1);
 
     int i, master = pos.thread();
     Thread& masterThread = threads[master];
 
-    lock_grab(&MPLock);
+    lock_grab(&mpLock);
 
     // If no other thread is available to help us, or if we have too many
     // active split points, don't split.
     if (   !available_thread_exists(master)
         || masterThread.activeSplitPoints >= MAX_ACTIVE_SPLIT_POINTS)
     {
-        lock_release(&MPLock);
+        lock_release(&mpLock);
         return;
     }
 
@@ -2451,6 +2500,7 @@ split_point_start: // At split points actual search starts from here
 
     // Initialize the split point object
     splitPoint.parent = masterThread.splitPoint;
+    splitPoint.master = master;
     splitPoint.stopRequest = false;
     splitPoint.ply = ply;
     splitPoint.depth = depth;
@@ -2465,7 +2515,7 @@ split_point_start: // At split points actual search starts from here
     splitPoint.pos = &pos;
     splitPoint.nodes = 0;
     splitPoint.parentSstack = ss;
-    for (i = 0; i < ActiveThreads; i++)
+    for (i = 0; i < activeThreads; i++)
         splitPoint.slaves[i] = 0;
 
     masterThread.splitPoint = &splitPoint;
@@ -2476,7 +2526,7 @@ split_point_start: // At split points actual search starts from here
     int workersCnt = 1; // At least the master is included
 
     // Allocate available threads setting state to THREAD_BOOKED
-    for (i = 0; !Fake && i < ActiveThreads && workersCnt < MaxThreadsPerSplitPoint; i++)
+    for (i = 0; !Fake && i < activeThreads && workersCnt < maxThreadsPerSplitPoint; i++)
         if (thread_is_available(i, master))
         {
             threads[i].state = THREAD_BOOKED;
@@ -2488,11 +2538,11 @@ split_point_start: // At split points actual search starts from here
     assert(Fake || workersCnt > 1);
 
     // We can release the lock because slave threads are already booked and master is not available
-    lock_release(&MPLock);
+    lock_release(&mpLock);
 
     // Tell the threads that they have work to do. This will make them leave
     // their idle loop. But before copy search stack tail for each thread.
-    for (i = 0; i < ActiveThreads; i++)
+    for (i = 0; i < activeThreads; i++)
         if (i == master || splitPoint.slaves[i])
         {
             memcpy(splitPoint.sstack[i], ss - 1, 4 * sizeof(SearchStack));
@@ -2500,7 +2550,8 @@ split_point_start: // At split points actual search starts from here
             assert(i == master || threads[i].state == THREAD_BOOKED);
 
             threads[i].state = THREAD_WORKISWAITING; // This makes the slave to exit from idle_loop()
-            if (i != master)
+
+            if (useSleepingThreads && i != master)
                 wake_sleeping_thread(i);
         }
 
@@ -2513,7 +2564,7 @@ split_point_start: // At split points actual search starts from here
 
     // We have returned from the idle loop, which means that all threads are
     // finished. Update alpha and bestValue, and return.
-    lock_grab(&MPLock);
+    lock_grab(&mpLock);
 
     *alpha = splitPoint.alpha;
     *bestValue = splitPoint.bestValue;
@@ -2521,18 +2572,18 @@ split_point_start: // At split points actual search starts from here
     masterThread.splitPoint = splitPoint.parent;
     pos.set_nodes_searched(pos.nodes_searched() + splitPoint.nodes);
 
-    lock_release(&MPLock);
+    lock_release(&mpLock);
   }
 
 
-  // wake_sleeping_thread() wakes up all sleeping threads when it is time
-  // to start a new search from the root.
+  // wake_sleeping_thread() wakes up the thread with the given threadID
+  // when it is time to start a new search.
 
   void ThreadsManager::wake_sleeping_thread(int threadID) {
 
-     lock_grab(&MPLock);
-     cond_signal(&WaitCond[threadID]);
-     lock_release(&MPLock);
+     lock_grab(&sleepLock[threadID]);
+     cond_signal(&sleepCond[threadID]);
+     lock_release(&sleepLock[threadID]);
   }