for (size_t i = 0; i < fens.size(); i++)
{
- Position pos(fens[i], Options["UCI_Chess960"], Threads.main_thread());
+ Position pos(fens[i], Options["UCI_Chess960"], Threads.main());
cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl;
{
Signals.firstRootMove = (moveCount == 1);
- if (thisThread == Threads.main_thread() && Time::now() - SearchTime > 3000)
+ if (thisThread == Threads.main() && Time::now() - SearchTime > 3000)
sync_cout << "info depth " << depth / ONE_PLY
<< " currmove " << move_to_uci(move, pos.is_chess960())
<< " currmovenumber " << moveCount + PVIdx << sync_endl;
// start_routine() is the C function which is called when a new thread
// is launched. It is a wrapper to the virtual function idle_loop().
- extern "C" { long start_routine(Thread* th) { th->idle_loop(); return 0; } }
+ extern "C" { long start_routine(ThreadBase* th) { th->idle_loop(); return 0; } }
// Helpers to launch a thread after creation and joining before delete. Must be
template<typename T> T* new_thread() {
T* th = new T();
- thread_create(th->handle, start_routine, th);
+ thread_create(th->handle, start_routine, th); // Will go to sleep
return th;
}
- void delete_thread(Thread* th) {
+ void delete_thread(ThreadBase* th) {
th->exit = true; // Search must be already finished
th->notify_one();
thread_join(th->handle); // Wait for thread termination
}
-// Thread c'tor starts a newly-created thread of execution that will call
-// the the virtual function idle_loop(), going immediately to sleep.
+// ThreadBase::notify_one() wakes up the thread when there is some work to do
+
+void ThreadBase::notify_one() {
+
+ mutex.lock();
+ sleepCondition.notify_one();
+ mutex.unlock();
+}
+
+
+// ThreadBase::wait_for() set the thread to sleep until condition 'b' turns true
+
+void ThreadBase::wait_for(volatile const bool& b) {
+
+ mutex.lock();
+ while (!b) sleepCondition.wait(mutex);
+ mutex.unlock();
+}
+
+
+// Thread c'tor just inits data but does not launch any thread of execution that
+// instead will be started only upon c'tor returns.
Thread::Thread() /* : splitPoints() */ { // Value-initialization bug in MSVC
- searching = exit = false;
+ searching = false;
maxPly = splitPointsSize = 0;
activeSplitPoint = NULL;
activePosition = NULL;
}
-// Thread::notify_one() wakes up the thread when there is some search to do
-
-void Thread::notify_one() {
-
- mutex.lock();
- sleepCondition.notify_one();
- mutex.unlock();
-}
-
-
-// Thread::wait_for() set the thread to sleep until condition 'b' turns true
-
-void Thread::wait_for(volatile const bool& b) {
-
- mutex.lock();
- while (!b) sleepCondition.wait(mutex);
- mutex.unlock();
-}
-
-
// Thread::cutoff_occurred() checks whether a beta cutoff has occurred in the
// current active split point, or in some ancestor of the split point.
void ThreadPool::wait_for_think_finished() {
- MainThread* t = main_thread();
+ MainThread* t = main();
t->mutex.lock();
while (t->thinking) sleepCondition.wait(t->mutex);
t->mutex.unlock();
|| std::count(searchMoves.begin(), searchMoves.end(), *it))
RootMoves.push_back(RootMove(*it));
- main_thread()->thinking = true;
- main_thread()->notify_one(); // Starts main thread
+ main()->thinking = true;
+ main()->notify_one(); // Starts main thread
}
};
+/// ThreadBase struct is the base of the hierarchy from where we derive all the
+/// specialized thread classes.
+
+struct ThreadBase {
+
+ ThreadBase() : exit(false) {}
+ virtual ~ThreadBase() {}
+ virtual void idle_loop() = 0;
+ void notify_one();
+ void wait_for(volatile const bool& b);
+
+ Mutex mutex;
+ ConditionVariable sleepCondition;
+ NativeHandle handle;
+ volatile bool exit;
+};
+
+
/// Thread struct keeps together all the thread related stuff like locks, state
/// and especially split points. We also use per-thread pawn and material hash
/// tables so that once we get a pointer to an entry its life time is unlimited
/// and we don't have to care about someone changing the entry under our feet.
-struct Thread {
+struct Thread : public ThreadBase {
Thread();
- virtual ~Thread() {}
-
virtual void idle_loop();
- void notify_one();
bool cutoff_occurred() const;
bool is_available_to(Thread* master) const;
- void wait_for(volatile const bool& b);
template <bool Fake>
void split(Position& pos, Search::Stack* ss, Value alpha, Value beta, Value* bestValue, Move* bestMove,
Position* activePosition;
size_t idx;
int maxPly;
- Mutex mutex;
- ConditionVariable sleepCondition;
- NativeHandle handle;
SplitPoint* volatile activeSplitPoint;
volatile int splitPointsSize;
volatile bool searching;
- volatile bool exit;
};
-/// MainThread and TimerThread are sublassed from Thread to characterize the two
+/// MainThread and TimerThread are derived classes used to characterize the two
/// special threads: the main one and the recurring timer.
struct MainThread : public Thread {
volatile bool thinking;
};
-struct TimerThread : public Thread {
+struct TimerThread : public ThreadBase {
TimerThread() : msec(0) {}
virtual void idle_loop();
int msec;
void init(); // No c'tor and d'tor, threads rely on globals that should
void exit(); // be initialized and valid during the whole thread lifetime.
- MainThread* main_thread() { return static_cast<MainThread*>((*this)[0]); }
+ MainThread* main() { return static_cast<MainThread*>((*this)[0]); }
void read_uci_options();
Thread* available_slave(Thread* master) const;
void wait_for_think_finished();
void UCI::loop(const string& args) {
- Position pos(StartFEN, false, Threads.main_thread()); // The root position
+ Position pos(StartFEN, false, Threads.main()); // The root position
string token, cmd = args;
do {
if (token != "ponderhit" || Search::Signals.stopOnPonderhit)
{
Search::Signals.stop = true;
- Threads.main_thread()->notify_one(); // Could be sleeping
+ Threads.main()->notify_one(); // Could be sleeping
}
else
Search::Limits.ponder = false;
else
return;
- pos.set(fen, Options["UCI_Chess960"], Threads.main_thread());
+ pos.set(fen, Options["UCI_Chess960"], Threads.main());
SetupStates = Search::StateStackPtr(new std::stack<StateInfo>());
// Parse move list (if any)