- // 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);
-
- threads[threadID].state = THREAD_SEARCHING;
-
- // Here we call search() with SplitPoint template parameter set to true
- SplitPoint* tsp = threads[threadID].splitPoint;
- Position pos(*tsp->pos, threadID);
- SearchStack* ss = tsp->sstack[threadID] + 1;
- ss->sp = tsp;
-
- if (tsp->pvNode)
- search<PV, true>(pos, ss, tsp->alpha, tsp->beta, tsp->depth, tsp->ply);
- 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.
- for (i = 0; sp && i < activeThreads && !sp->slaves[i]; i++) {}
- allFinished = (i == activeThreads);
-
- if (allFinished)
- {
- // Because sp->slaves[] is reset under lock protection,
- // be sure sp->lock has been released before to return.
- lock_grab(&(sp->lock));
- lock_release(&(sp->lock));
-
- // 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(threads[threadID].state == THREAD_AVAILABLE);
-
- threads[threadID].state = THREAD_SEARCHING;
- return;
- }
- }
- }
-
-
- // init_threads() is called during startup. It launches all helper threads,
- // and initializes the split point stack and the global locks and condition
- // objects.
-
- void ThreadsManager::init_threads() {
-
- int i, arg[MAX_THREADS];
- bool ok;
-
- // Initialize global locks
- lock_init(&mpLock);
-
- for (i = 0; i < MAX_THREADS; i++)
- {
- lock_init(&sleepLock[i]);
- cond_init(&sleepCond[i]);
- }
-
- // Initialize splitPoints[] locks
- for (i = 0; i < MAX_THREADS; i++)
- for (int j = 0; j < MAX_ACTIVE_SPLIT_POINTS; j++)
- lock_init(&(threads[i].splitPoints[j].lock));
-
- // Will be set just before program exits to properly end the threads
- allThreadsShouldExit = false;
-
- // Threads will be put all threads to sleep as soon as created
- activeThreads = 1;
-
- // All threads except the main thread should be initialized to THREAD_INITIALIZING
- threads[0].state = THREAD_SEARCHING;
- for (i = 1; i < MAX_THREADS; i++)
- threads[i].state = THREAD_INITIALIZING;
-
- // Launch the helper threads
- for (i = 1; i < MAX_THREADS; i++)
- {
- arg[i] = i;
-
-#if !defined(_MSC_VER)
- pthread_t pthread[1];
- ok = (pthread_create(pthread, NULL, init_thread, (void*)(&arg[i])) == 0);
- pthread_detach(pthread[0]);
-#else
- ok = (CreateThread(NULL, 0, init_thread, (LPVOID)(&arg[i]), 0, NULL) != NULL);
-#endif
- if (!ok)
- {
- cout << "Failed to create thread number " << i << endl;
- exit(EXIT_FAILURE);
- }
-
- // Wait until the thread has finished launching and is gone to sleep
- while (threads[i].state == THREAD_INITIALIZING) {}
- }
- }
-
-
- // exit_threads() is called when the program exits. It makes all the
- // helper threads exit cleanly.
-
- void ThreadsManager::exit_threads() {
-
- 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++)
- {
- wake_sleeping_thread(i);
- while (threads[i].state != THREAD_TERMINATED) {}
- }
-
- // Now we can safely destroy the locks
- for (int i = 0; i < MAX_THREADS; i++)
- for (int j = 0; j < MAX_ACTIVE_SPLIT_POINTS; j++)
- lock_destroy(&(threads[i].splitPoints[j].lock));
-
- lock_destroy(&mpLock);
-
- // Now we can safely destroy the wait conditions
- for (int i = 0; i < MAX_THREADS; i++)
- {
- lock_destroy(&sleepLock[i]);
- cond_destroy(&sleepCond[i]);
- }
- }
-
-
- // cutoff_at_splitpoint() checks whether a beta cutoff has occurred in
- // the thread's currently active split point, or in some ancestor of
- // the current split point.
-
- bool ThreadsManager::cutoff_at_splitpoint(int threadID) const {
-
- assert(threadID >= 0 && threadID < activeThreads);
-
- SplitPoint* sp = threads[threadID].splitPoint;
-
- for ( ; sp && !sp->betaCutoff; sp = sp->parent) {}
- return sp != NULL;
- }
-
-
- // thread_is_available() checks whether the thread with threadID "slave" is
- // available to help the thread with threadID "master" at a split point. An
- // obvious requirement is that "slave" must be idle. With more than two
- // threads, this is not by itself sufficient: If "slave" is the master of
- // some active split point, it is only available as a slave to the other
- // threads which are busy searching the split point at the top of "slave"'s
- // split point stack (the "helpful master concept" in YBWC terminology).
-
- bool ThreadsManager::thread_is_available(int slave, int master) const {
-
- assert(slave >= 0 && slave < activeThreads);
- assert(master >= 0 && master < activeThreads);
- assert(activeThreads > 1);
-
- if (threads[slave].state != THREAD_AVAILABLE || slave == master)
- return false;
-
- // Make a local copy to be sure doesn't change under our feet
- int localActiveSplitPoints = threads[slave].activeSplitPoints;
-
- // No active split points means that the thread is available as
- // a slave for any other thread.
- if (localActiveSplitPoints == 0 || activeThreads == 2)
- return true;
-
- // Apply the "helpful master" concept if possible. Use localActiveSplitPoints
- // that is known to be > 0, instead of threads[slave].activeSplitPoints that
- // could have been set to 0 by another thread leading to an out of bound access.
- if (threads[slave].splitPoints[localActiveSplitPoints - 1].slaves[master])
- return true;
-
- return false;
- }
-
-
- // available_thread_exists() tries to find an idle thread which is available as
- // a slave for the thread with threadID "master".
-
- bool ThreadsManager::available_thread_exists(int master) const {
-
- assert(master >= 0 && master < activeThreads);
- assert(activeThreads > 1);
-
- for (int i = 0; i < activeThreads; i++)
- if (thread_is_available(i, master))
- return true;
-
- return false;