Thread Threads[THREAD_MAX];
Lock MPLock;
Lock IOLock;
- bool AllThreadsShouldExit = false;
+ bool AllThreadsShouldExit, AllThreadsShouldSleep;
SplitPoint SplitPointStack[THREAD_MAX][ACTIVE_SPLIT_POINTS_MAX];
- bool Idle = true;
#if !defined(_MSC_VER)
pthread_cond_t WaitCond;
const Value futilityValue, Depth depth, int *moves,
MovePicker *mp, int master, bool pvNode);
void wake_sleeping_threads();
+ void put_threads_to_sleep();
#if !defined(_MSC_VER)
void *init_thread(void *threadID);
int maxNodes, int maxTime, Move searchMoves[]) {
// Initialize global search variables
- Idle = StopOnPonderhit = AbortSearch = Quit = false;
+ StopOnPonderhit = AbortSearch = Quit = false;
AspirationFailLow = false;
NodesSincePoll = 0;
SearchStartTime = get_system_time();
if (UseLogFile)
LogFile.close();
- Idle = true;
+ put_threads_to_sleep();
+
return !Quit;
}
pthread_t pthread[1];
#endif
- for (i = 0; i < THREAD_MAX; i++)
- Threads[i].activeSplitPoints = 0;
-
// Initialize global locks
lock_init(&MPLock, NULL);
lock_init(&IOLock, NULL);
SitIdleEvent[i] = CreateEvent(0, FALSE, FALSE, 0);
#endif
+ // Will be set just before program exits to properly end the threads
+ AllThreadsShouldExit = false;
+
+ // Threads will be put to sleep as soon as created
+ AllThreadsShouldSleep = true;
+
// All threads except the main thread should be initialized to idle state
for (i = 1; i < THREAD_MAX; i++)
- {
- Threads[i].stop = false;
- Threads[i].workIsWaiting = false;
Threads[i].idle = true;
- Threads[i].running = false;
- }
// Launch the helper threads
for (i = 1; i < THREAD_MAX; i++)
Application::exit_with_failure();
}
- // Wait until the thread has finished launching
- while (!Threads[i].running);
+ // Wait until the thread has finished launching and is gone to sleep
+ while (!Threads[i].running || !Threads[i].sleeping);
}
}
-/// stop_threads() is called when the program exits. It makes all the
+/// exit_threads() is called when the program exits. It makes all the
/// helper threads exit cleanly.
-void stop_threads() {
+void exit_threads() {
ActiveThreads = THREAD_MAX; // HACK
- Idle = false; // HACK
+ AllThreadsShouldSleep = true; // HACK
wake_sleeping_threads();
AllThreadsShouldExit = true;
for (int i = 1; i < THREAD_MAX; i++)
currentMove = threatMove = MOVE_NONE;
reduction = Depth(0);
eval = VALUE_NONE;
- evalInfo = NULL;
}
void SearchStack::initKillers() {
if (tte && (tte->type() & VALUE_TYPE_EVAL))
staticValue = value_from_tt(tte->value(), ply);
else
- {
staticValue = evaluate(pos, ei, threadID);
- ss[ply].evalInfo = &ei;
- }
ss[ply].eval = staticValue;
futilityValue = staticValue + futility_margin(depth, 0); //FIXME: Remove me, only for split
Threads[threadID].running = true;
- while (true)
+ while (!AllThreadsShouldExit || threadID == 0)
{
- if (AllThreadsShouldExit && threadID != 0)
- break;
-
// If we are not thinking, wait for a condition to be signaled
// instead of wasting CPU time polling for work.
- while (threadID != 0 && (Idle || threadID >= ActiveThreads))
+ while ( threadID != 0
+ && !AllThreadsShouldExit
+ && (AllThreadsShouldSleep || threadID >= ActiveThreads))
{
+ Threads[threadID].sleeping = true;
+
#if !defined(_MSC_VER)
pthread_mutex_lock(&WaitLock);
if (Idle || threadID >= ActiveThreads)
#endif
}
+ // Out of the while loop to avoid races in case thread is woken up but
+ // while condition still holds true so that is put to sleep again.
+ Threads[threadID].sleeping = false;
+
// If this thread has been assigned work, launch a search
if (Threads[threadID].workIsWaiting)
{
void wake_sleeping_threads() {
+ assert(AllThreadsShouldSleep);
+
+ AllThreadsShouldSleep = false;
+
if (ActiveThreads > 1)
{
for (int i = 1; i < ActiveThreads; i++)
{
+ assert(Threads[i].sleeping == true);
+
Threads[i].idle = true;
Threads[i].workIsWaiting = false;
}
for (int i = 1; i < THREAD_MAX; i++)
SetEvent(SitIdleEvent[i]);
#endif
+
+ // Wait for the threads to be all woken up
+ for (int i = 1; i < ActiveThreads; i++)
+ while (Threads[i].sleeping);
}
}
+ // put_threads_to_sleep() makes all the threads go to sleep just before
+ // to leave think(), at the end of the search. Threads should have already
+ // finished the job and should be idle.
+
+ void put_threads_to_sleep() {
+
+ assert(!AllThreadsShouldSleep);
+
+ AllThreadsShouldSleep = true;
+
+ // Wait for the threads to be all sleeping
+ for (int i = 1; i < ActiveThreads; i++)
+ while (!Threads[i].sleeping);
+ }
+
+
// init_thread() is the function which is called when a new thread is
// launched. It simply calls the idle_loop() function with the supplied
// threadID. There are two versions of this function; one for POSIX