Skip to content

Commit

Permalink
Move ThreadsManager::exit() to d'tor
Browse files Browse the repository at this point in the history
And add final touches to this long patch series.

All the series has been verified against regression with
20K games at fast TC.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
  • Loading branch information
mcostalba committed Mar 26, 2012
1 parent b978eb0 commit 32d3a07
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 65 deletions.
2 changes: 0 additions & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,4 @@ int main(int argc, char* argv[]) {
cerr << "\nUsage: stockfish bench [hash size = 128] [threads = 1] "
<< "[limit = 12] [fen positions file = default] "
<< "[limited by depth, time, nodes or perft = depth]" << endl;

Threads.exit();
}
112 changes: 55 additions & 57 deletions src/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ ThreadsManager Threads; // Global object
namespace { extern "C" {

// start_routine() is the C function which is called when a new thread
// is launched. It is a wrapper to member function pointed by start_fn
// is launched. It is a wrapper to member function pointed by start_fn.

long start_routine(Thread* th) { (th->*(th->start_fn))(); return 0; }

Expand All @@ -49,7 +49,8 @@ Thread::Thread(Fn fn) {
curSplitPoint = NULL;
start_fn = fn;
threadID = Threads.size();
do_sleep = (threadID != 0); // Avoid a race with start_thinking()

do_sleep = (fn != &Thread::main_loop); // Avoid a race with start_thinking()

lock_init(sleepLock);
cond_init(sleepCond);
Expand All @@ -65,7 +66,7 @@ Thread::Thread(Fn fn) {
}


// Thread d'tor will wait for thread termination before to return.
// Thread d'tor waits for thread termination before to return.

Thread::~Thread() {

Expand All @@ -85,7 +86,7 @@ Thread::~Thread() {


// Thread::timer_loop() is where the timer thread waits maxPly milliseconds and
// then calls do_timer_event(). If maxPly is 0 thread sleeps until is woken up.
// then calls check_time(). If maxPly is 0 thread sleeps until is woken up.
extern void check_time();

void Thread::timer_loop() {
Expand Down Expand Up @@ -131,7 +132,7 @@ void Thread::main_loop() {


// Thread::wake_up() wakes up the thread, normally at the beginning of the search
// or, if "sleeping threads" is used, when there is some work to do.
// or, if "sleeping threads" is used at split time.

void Thread::wake_up() {

Expand Down Expand Up @@ -161,8 +162,8 @@ void Thread::wait_for_stop_or_ponderhit() {
}


// cutoff_occurred() checks whether a beta cutoff has occurred in the current
// active split point, or in some ancestor of the split point.
// Thread::cutoff_occurred() checks whether a beta cutoff has occurred in the
// current active split point, or in some ancestor of the split point.

bool Thread::cutoff_occurred() const {

Expand All @@ -174,12 +175,12 @@ bool Thread::cutoff_occurred() const {
}


// is_available_to() checks whether the thread is available to help the thread with
// threadID "master" at a split point. An obvious requirement is that thread must be
// idle. With more than two threads, this is not by itself sufficient: If the thread
// is the master of some active split point, it is only available as a slave to the
// threads which are busy searching the split point at the top of "slave"'s split
// point stack (the "helpful master concept" in YBWC terminology).
// Thread::is_available_to() checks whether the thread is available to help the
// thread with threadID "master" at a split point. An obvious requirement is that
// thread must be idle. With more than two threads, this is not sufficient: If
// the thread is the master of some active split point, it is only available as a
// slave to the 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 Thread::is_available_to(int master) const {

Expand All @@ -196,6 +197,34 @@ bool Thread::is_available_to(int master) const {
}


// init() is called at startup. Initializes lock and condition variable and
// launches requested threads sending them immediately to sleep. We cannot use
// a c'tor becuase Threads is a static object and we need a fully initialized
// engine at this point due to allocation of endgames in Thread c'tor.

void ThreadsManager::init() {

cond_init(sleepCond);
lock_init(splitLock);
timer = new Thread(&Thread::timer_loop);
threads.push_back(new Thread(&Thread::main_loop));
read_uci_options();
}


// d'tor cleanly terminates the threads when the program exits.

ThreadsManager::~ThreadsManager() {

for (int i = 0; i < size(); i++)
delete threads[i];

delete timer;
lock_destroy(splitLock);
cond_destroy(sleepCond);
}


// read_uci_options() updates internal threads parameters from the corresponding
// UCI options and creates/destroys threads to match the requested number. Thread
// objects are dynamically allocated to avoid creating in advance all possible
Expand All @@ -222,10 +251,10 @@ void ThreadsManager::read_uci_options() {


// wake_up() is called before a new search to start the threads that are waiting
// on the sleep condition. If useSleepingThreads is set threads will be woken up
// at split time.
// on the sleep condition and to reset maxPly. When useSleepingThreads is set
// threads will be woken up at split time.

void ThreadsManager::wake_up() {
void ThreadsManager::wake_up() const {

for (int i = 0; i < size(); i++)
{
Expand All @@ -238,42 +267,16 @@ void ThreadsManager::wake_up() {
}


// sleep() is called after the search to ask all the threads but the main to go
// waiting on a sleep condition.
// sleep() is called after the search finishes to ask all the threads but the
// main one to go waiting on a sleep condition.

void ThreadsManager::sleep() {
void ThreadsManager::sleep() const {

for (int i = 1; i < size(); i++) // Main thread will go to sleep by itself
threads[i]->do_sleep = true; // to avoid a race with start_thinking()
}


// init() is called during startup. Initializes locks and condition variables
// and launches all threads sending them immediately to sleep.

void ThreadsManager::init() {

cond_init(sleepCond);
lock_init(splitLock);
timer = new Thread(&Thread::timer_loop);
threads.push_back(new Thread(&Thread::main_loop));
read_uci_options();
}


// exit() is called to cleanly terminate the threads before the program finishes

void ThreadsManager::exit() {

for (int i = 0; i < size(); i++)
delete threads[i];

delete timer;
lock_destroy(splitLock);
cond_destroy(sleepCond);
}


// available_slave_exists() tries to find an idle thread which is available as
// a slave for the thread with threadID 'master'.

Expand Down Expand Up @@ -413,7 +416,7 @@ void ThreadsManager::set_timer(int msec) {


// ThreadsManager::start_thinking() is used by UI thread to wake up the main
// thread parked in main_loop() and starting a new search. If asyncMode is true
// thread parked in main_loop() and starting a new search. If async is true
// then function returns immediately, otherwise caller is blocked waiting for
// the search to finish.

Expand All @@ -423,25 +426,20 @@ void ThreadsManager::start_thinking(const Position& pos, const LimitsType& limit

lock_grab(main.sleepLock);

// Wait main thread has finished before to launch a new search
while (!main.do_sleep)
cond_wait(sleepCond, main.sleepLock);
cond_wait(sleepCond, main.sleepLock); // Wait main thread has finished

Signals.stopOnPonderhit = Signals.firstRootMove = false;
Signals.stop = Signals.failedLowAtRoot = false;

// Copy input arguments to initialize the search
RootPosition.copy(pos, 0);
Limits = limits;
RootMoves.clear();

// Populate RootMoves with all the legal moves (default) or, if a searchMoves
// set is given, with the subset of legal moves to search.
for (MoveList<MV_LEGAL> ml(pos); !ml.end(); ++ml)
if (searchMoves.empty() || searchMoves.count(ml.move()))
RootMoves.push_back(RootMove(ml.move()));

// Reset signals before to start the new search
Signals.stopOnPonderhit = Signals.firstRootMove = false;
Signals.stop = Signals.failedLowAtRoot = false;

main.do_sleep = false;
cond_signal(main.sleepCond); // Wake up main thread and start searching

Expand All @@ -454,8 +452,8 @@ void ThreadsManager::start_thinking(const Position& pos, const LimitsType& limit


// ThreadsManager::stop_thinking() is used by UI thread to raise a stop request
// and to wait for the main thread finishing the search. Needed to wait exiting
// and terminate the threads after a 'quit' command.
// and to wait for the main thread finishing the search. We cannot return before
// main has finished to avoid a crash in case of a 'quit' command.

void ThreadsManager::stop_thinking() {

Expand Down
8 changes: 4 additions & 4 deletions src/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,16 +112,16 @@ class ThreadsManager {
static storage duration are automatically set to zero before enter main()
*/
public:
void init();
void exit();
void init(); // No c'tor becuase Threads is static and we need stuff initialized
~ThreadsManager();

Thread& operator[](int id) { return *threads[id]; }
bool use_sleeping_threads() const { return useSleepingThreads; }
int min_split_depth() const { return minimumSplitDepth; }
int size() const { return (int)threads.size(); }

void wake_up();
void sleep();
void wake_up() const;
void sleep() const;
void read_uci_options();
bool available_slave_exists(int master) const;
void set_timer(int msec);
Expand Down
4 changes: 2 additions & 2 deletions src/tt.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ inline void TranspositionTable::refresh(const TTEntry* tte) const {

/// A simple fixed size hash table used to store pawns and material
/// configurations. It is basically just an array of Entry objects.
/// Without cluster concept or overwrite policy.
/// Without cluster concept, overwrite policy nor resizing.

template<class Entry, int HashSize>
struct SimpleHash {
Expand All @@ -153,7 +153,7 @@ struct SimpleHash {
{
std::cerr << "Failed to allocate " << HashSize * sizeof(Entry)
<< " bytes for hash table." << std::endl;
exit(EXIT_FAILURE);
::exit(EXIT_FAILURE);
}
memset(entries, 0, HashSize * sizeof(Entry));
}
Expand Down

0 comments on commit 32d3a07

Please sign in to comment.