summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
189a005)
This is easier to follow and also reduces the points
where state changes to mainly idle_loop() and split().
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
friend void poll();
int ActiveThreads;
friend void poll();
int ActiveThreads;
- bool AllThreadsShouldExit, AllThreadsShouldSleep;
+ volatile bool AllThreadsShouldExit, AllThreadsShouldSleep;
Thread threads[MAX_THREADS];
SplitPoint SplitPointStack[MAX_THREADS][ACTIVE_SPLIT_POINTS_MAX];
Thread threads[MAX_THREADS];
SplitPoint SplitPointStack[MAX_THREADS][ACTIVE_SPLIT_POINTS_MAX];
assert(threadID >= 0 && threadID < MAX_THREADS);
assert(threadID >= 0 && threadID < MAX_THREADS);
- threads[threadID].running = true;
-
- while (!AllThreadsShouldExit || threadID == 0)
+ // Slave threads can exit as soon as AllThreadsShouldExit raises,
+ // master should exit as last one.
+ if (AllThreadsShouldExit && !waitSp)
+ {
+ threads[threadID].state = THREAD_TERMINATED;
+ return;
+ }
+
// If we are not thinking, wait for a condition to be signaled
// instead of wasting CPU time polling for work.
while ( threadID != 0
&& !AllThreadsShouldExit
&& (AllThreadsShouldSleep || threadID >= ActiveThreads))
{
// If we are not thinking, wait for a condition to be signaled
// instead of wasting CPU time polling for work.
while ( threadID != 0
&& !AllThreadsShouldExit
&& (AllThreadsShouldSleep || threadID >= ActiveThreads))
{
-
- threads[threadID].sleeping = true;
+ threads[threadID].state = THREAD_SLEEPING;
#if !defined(_MSC_VER)
pthread_mutex_lock(&WaitLock);
#if !defined(_MSC_VER)
pthread_mutex_lock(&WaitLock);
- if (AllThreadsShouldSleep || threadID >= ActiveThreads)
- pthread_cond_wait(&WaitCond, &WaitLock);
-
+ pthread_cond_wait(&WaitCond, &WaitLock);
pthread_mutex_unlock(&WaitLock);
#else
WaitForSingleObject(SitIdleEvent[threadID], INFINITE);
#endif
pthread_mutex_unlock(&WaitLock);
#else
WaitForSingleObject(SitIdleEvent[threadID], INFINITE);
#endif
+ // State is already changed by wake_sleeping_threads()
+ assert(threads[threadID].state == THREAD_AVAILABLE || threadID >= ActiveThreads);
- // 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 this thread has been assigned work, launch a search
- if (threads[threadID].workIsWaiting)
+ if (threads[threadID].state == THREAD_WORKISWAITING)
- assert(!threads[threadID].idle);
+ threads[threadID].state = THREAD_SEARCHING;
- threads[threadID].workIsWaiting = false;
if (threads[threadID].splitPoint->pvNode)
sp_search_pv(threads[threadID].splitPoint, threadID);
else
sp_search(threads[threadID].splitPoint, threadID);
if (threads[threadID].splitPoint->pvNode)
sp_search_pv(threads[threadID].splitPoint, threadID);
else
sp_search(threads[threadID].splitPoint, threadID);
- threads[threadID].idle = true;
+ assert(threads[threadID].state == THREAD_SEARCHING);
+
+ // If this is a slave thread reset to available, instead
+ // if it is a master thread and all slaves have finished
+ // then leave as is to avoid booking by another master,
+ // we will leave idle loop shortly anyhow.
+ if ( !AllThreadsShouldExit
+ && (!waitSp || waitSp->cpus > 0))
+ threads[threadID].state = THREAD_AVAILABLE;
}
// If this thread is the master of a split point and all threads have
// finished their work at this split point, return from the idle loop.
if (waitSp != NULL && waitSp->cpus == 0)
}
// If this thread is the master of a split point and all threads have
// finished their work at this split point, return from the idle loop.
if (waitSp != NULL && waitSp->cpus == 0)
+ {
+ assert( threads[threadID].state == THREAD_AVAILABLE
+ || threads[threadID].state == THREAD_SEARCHING);
+
+ threads[threadID].state = THREAD_SEARCHING;
-
- threads[threadID].running = false;
// Threads will be put to sleep as soon as created
AllThreadsShouldSleep = true;
// Threads will be put to sleep as soon as created
AllThreadsShouldSleep = true;
- // All threads except the main thread should be initialized to idle state
+ // All threads except the main thread should be initialized to THREAD_AVAILABLE
+ threads[0].state = THREAD_SEARCHING;
for (i = 1; i < MAX_THREADS; i++)
for (i = 1; i < MAX_THREADS; i++)
- threads[i].idle = true;
+ threads[i].state = THREAD_AVAILABLE;
// Launch the helper threads
for (i = 1; i < MAX_THREADS; i++)
// Launch the helper threads
for (i = 1; i < MAX_THREADS; i++)
}
// Wait until the thread has finished launching and is gone to sleep
}
// Wait until the thread has finished launching and is gone to sleep
- while (!threads[i].running || !threads[i].sleeping);
+ while (threads[i].state != THREAD_SLEEPING);
ActiveThreads = MAX_THREADS; // HACK
AllThreadsShouldSleep = true; // HACK
wake_sleeping_threads();
ActiveThreads = MAX_THREADS; // HACK
AllThreadsShouldSleep = true; // HACK
wake_sleeping_threads();
+
+ // This makes the threads to exit idle_loop()
AllThreadsShouldExit = true;
AllThreadsShouldExit = true;
+
+ // Wait for thread termination
for (int i = 1; i < MAX_THREADS; i++)
for (int i = 1; i < MAX_THREADS; i++)
- {
- threads[i].stopRequest = true;
- while (threads[i].running);
- }
+ while (threads[i].state != THREAD_TERMINATED)
+ threads[i].stopRequest = true;
// Now we can safely destroy the locks
for (int i = 0; i < MAX_THREADS; i++)
// Now we can safely destroy the locks
for (int i = 0; i < MAX_THREADS; i++)
assert(master >= 0 && master < ActiveThreads);
assert(ActiveThreads > 1);
assert(master >= 0 && master < ActiveThreads);
assert(ActiveThreads > 1);
- if (!threads[slave].idle || slave == master)
+ if (threads[slave].state != THREAD_AVAILABLE || slave == master)
return false;
// Make a local copy to be sure doesn't change under our feet
return false;
// Make a local copy to be sure doesn't change under our feet
threads[master].splitPoint = splitPoint;
threads[master].splitPoint = splitPoint;
- // If we are here it means we are not idle
- assert(!threads[master].idle);
+ // If we are here it means we are not available
+ assert(threads[master].state != THREAD_AVAILABLE);
- // Following assert could fail because we could be slave of a master
- // thread that has just raised a stop request. Note that stopRequest
- // can be changed with only splitPoint::lock held, not with MPLock.
- /* assert(!threads[master].stopRequest); */
-
- // Allocate available threads setting idle flag to false
+ // Allocate available threads setting state to THREAD_BOOKED
for (int i = 0; i < ActiveThreads && splitPoint->cpus < MaxThreadsPerSplitPoint; i++)
if (thread_is_available(i, master))
{
for (int i = 0; i < ActiveThreads && splitPoint->cpus < MaxThreadsPerSplitPoint; i++)
if (thread_is_available(i, master))
{
- threads[i].idle = false;
+ threads[i].state = THREAD_BOOKED;
threads[i].stopRequest = false;
threads[i].splitPoint = splitPoint;
splitPoint->slaves[i] = 1;
threads[i].stopRequest = false;
threads[i].splitPoint = splitPoint;
splitPoint->slaves[i] = 1;
assert(splitPoint->cpus > 1);
assert(splitPoint->cpus > 1);
- // We can release the lock because master and slave threads are already booked
+ // We can release the lock because slave threads are already booked and master is not available
lock_release(&MPLock);
// Tell the threads that they have work to do. This will make them leave
lock_release(&MPLock);
// Tell the threads that they have work to do. This will make them leave
if (i == master || splitPoint->slaves[i])
{
memcpy(splitPoint->sstack[i] + ply - 1, sstck + ply - 1, 4 * sizeof(SearchStack));
if (i == master || splitPoint->slaves[i])
{
memcpy(splitPoint->sstack[i] + ply - 1, sstck + ply - 1, 4 * sizeof(SearchStack));
- threads[i].workIsWaiting = true; // This makes the slave to exit from idle_loop()
+
+ assert(i == master || threads[i].state == THREAD_BOOKED);
+
+ threads[i].state = THREAD_WORKISWAITING; // This makes the slave to exit from idle_loop()
}
// Everything is set up. The master thread enters the idle loop, from
}
// Everything is set up. The master thread enters the idle loop, from
- // which it will instantly launch a search, because its workIsWaiting
- // slot is 'true'. We send the split point as a second parameter to the
+ // 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
// (i.e. when splitPoint->cpus == 0).
// 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
// (i.e. when splitPoint->cpus == 0).
*beta = splitPoint->beta;
*bestValue = splitPoint->bestValue;
threads[master].stopRequest = false;
*beta = splitPoint->beta;
*bestValue = splitPoint->bestValue;
threads[master].stopRequest = false;
- threads[master].idle = false;
threads[master].activeSplitPoints--;
threads[master].splitPoint = splitPoint->parent;
threads[master].activeSplitPoints--;
threads[master].splitPoint = splitPoint->parent;
for (int i = 1; i < ActiveThreads; i++)
{
for (int i = 1; i < ActiveThreads; i++)
{
- assert(threads[i].sleeping == true);
+ assert(threads[i].state == THREAD_SLEEPING);
- threads[i].idle = true;
- threads[i].workIsWaiting = false;
+ threads[i].state = THREAD_AVAILABLE;
SetEvent(SitIdleEvent[i]);
#endif
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
}
// 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
+ // to leave think(), at the end of the search. Threads should have already
// finished the job and should be idle.
void ThreadsManager::put_threads_to_sleep() {
assert(!AllThreadsShouldSleep);
// finished the job and should be idle.
void ThreadsManager::put_threads_to_sleep() {
assert(!AllThreadsShouldSleep);
+ // This makes the threads to go to sleep
AllThreadsShouldSleep = true;
// Wait for the threads to be all sleeping and reset flags
// to a known state.
for (int i = 1; i < ActiveThreads; i++)
{
AllThreadsShouldSleep = true;
// Wait for the threads to be all sleeping and reset flags
// to a known state.
for (int i = 1; i < ActiveThreads; i++)
{
- while (!threads[i].sleeping);
-
- assert(threads[i].idle);
- assert(threads[i].running);
- assert(!threads[i].workIsWaiting);
+ while (threads[i].state != THREAD_SLEEPING);
// These two flags can be in a random state
threads[i].stopRequest = threads[i].printCurrentLineRequest = false;
// These two flags can be in a random state
threads[i].stopRequest = threads[i].printCurrentLineRequest = false;
// One shot only
threads[threadID].printCurrentLineRequest = false;
// One shot only
threads[threadID].printCurrentLineRequest = false;
- if (!threads[threadID].idle)
+ if (threads[threadID].state == THREAD_SEARCHING)
{
lock_grab(&IOLock);
cout << "info currline " << (threadID + 1);
{
lock_grab(&IOLock);
cout << "info currline " << (threadID + 1);
+// ThreadState type is used to represent thread's current state
+
+enum ThreadState
+{
+ THREAD_SEARCHING, // thread is performing work
+ THREAD_AVAILABLE, // thread is polling for work
+ THREAD_SLEEPING, // we are not thinking, so thread is sleeping
+ THREAD_BOOKED, // other thread (master) has booked us as a slave
+ THREAD_WORKISWAITING, // master has ordered us to start
+ THREAD_TERMINATED // we are quitting and thread is terminated
+};
struct Thread {
SplitPoint *splitPoint;
struct Thread {
SplitPoint *splitPoint;
uint64_t nodes;
uint64_t betaCutOffs[2];
volatile bool stopRequest;
uint64_t nodes;
uint64_t betaCutOffs[2];
volatile bool stopRequest;
- volatile bool running;
- volatile bool idle;
- volatile bool sleeping;
- volatile bool workIsWaiting;
volatile bool printCurrentLineRequest;
volatile bool printCurrentLineRequest;
+ volatile ThreadState state;
unsigned char pad[64]; // set some distance among local data for each thread
};
unsigned char pad[64]; // set some distance among local data for each thread
};