mirror of
https://github.com/HChaZZY/Stockfish.git
synced 2025-12-24 19:16:49 +08:00
Remove multi_think
This commit is contained in:
@@ -59,8 +59,7 @@ SRCS = benchmark.cpp bitbase.cpp bitboard.cpp endgame.cpp evaluate.cpp main.cpp
|
||||
learn/sfen_packer.cpp \
|
||||
learn/learn.cpp \
|
||||
learn/gensfen.cpp \
|
||||
learn/convert.cpp \
|
||||
learn/multi_think.cpp
|
||||
learn/convert.cpp
|
||||
|
||||
OBJS = $(notdir $(SRCS:.cpp=.o))
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include "convert.h"
|
||||
|
||||
#include "multi_think.h"
|
||||
|
||||
#include "uci.h"
|
||||
#include "misc.h"
|
||||
#include "thread.h"
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
#include "multi_think.h"
|
||||
|
||||
#include "tt.h"
|
||||
#include "uci.h"
|
||||
#include "types.h"
|
||||
#include "search.h"
|
||||
|
||||
#include "nnue/evaluate_nnue.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
void MultiThink::go_think()
|
||||
{
|
||||
// Call the derived class's init().
|
||||
init();
|
||||
|
||||
// The loop upper limit is set with set_loop_max().
|
||||
loop_count = 0;
|
||||
done_count = 0;
|
||||
|
||||
// Create threads as many as Options["Threads"] and start thinking.
|
||||
std::vector<std::thread> threads;
|
||||
auto thread_num = (size_t)Options["Threads"];
|
||||
|
||||
// Secure end flag of worker thread
|
||||
threads_finished=0;
|
||||
|
||||
// start worker thread
|
||||
for (size_t i = 0; i < thread_num; ++i)
|
||||
{
|
||||
threads.push_back(std::thread([i, this]
|
||||
{
|
||||
// exhaust all processor threads.
|
||||
WinProcGroup::bindThisThread(i);
|
||||
|
||||
// execute the overridden process
|
||||
this->thread_worker(i);
|
||||
|
||||
// Set the end flag because the thread has ended
|
||||
this->threads_finished++;
|
||||
}));
|
||||
}
|
||||
|
||||
// wait for all threads to finish
|
||||
// for (auto& th :threads)
|
||||
// th.join();
|
||||
// If you write like, the thread will rush here while it is still working,
|
||||
// During that time, callback_func() cannot be called and you cannot save.
|
||||
// Therefore, you need to check the end flag yourself.
|
||||
|
||||
// function to determine if all threads have finished
|
||||
auto threads_done = [&]()
|
||||
{
|
||||
return threads_finished == thread_num;
|
||||
};
|
||||
|
||||
// Call back if the callback function is set.
|
||||
auto do_a_callback = [&]()
|
||||
{
|
||||
if (callback_func)
|
||||
callback_func();
|
||||
};
|
||||
|
||||
|
||||
for (uint64_t i = 0 ; ; )
|
||||
{
|
||||
// If all threads have finished, exit the loop.
|
||||
if (threads_done())
|
||||
break;
|
||||
|
||||
sleep(1000);
|
||||
|
||||
// callback_func() is called every callback_seconds.
|
||||
if (++i == callback_seconds)
|
||||
{
|
||||
do_a_callback();
|
||||
// Since I am returning from ↑, I reset the counter, so
|
||||
// no matter how long it takes to save() etc. in do_a_callback()
|
||||
// The next call will take a certain amount of time.
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Last save.
|
||||
std::cout << std::endl << "finalize..";
|
||||
|
||||
// do_a_callback();
|
||||
// → It should be saved by the caller, so I feel that it is not necessary here.
|
||||
|
||||
// It is possible that the exit code of the thread is running but the exit code of the thread is running, so
|
||||
// We need to wait for the end with join().
|
||||
for (auto& th : threads)
|
||||
th.join();
|
||||
|
||||
// The file writing thread etc. are still running only when all threads are finished
|
||||
// Since the work itself may not have completed, output only that all threads have finished.
|
||||
std::cout << "all threads are joined." << std::endl;
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
#ifndef _MULTI_THINK_
|
||||
#define _MULTI_THINK_
|
||||
|
||||
#include "learn.h"
|
||||
|
||||
#include "misc.h"
|
||||
#include "thread_win32_osx.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <limits>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
// Learning from a game record, when making yourself think and generating a fixed track, etc.
|
||||
// Helper class used when multiple threads want to call Search::think() individually.
|
||||
// Derive and use this class.
|
||||
struct MultiThink
|
||||
{
|
||||
static constexpr std::uint64_t LOOP_COUNT_FINISHED = std::numeric_limits<std::uint64_t>::max();
|
||||
|
||||
MultiThink() : prng{}, loop_count(0) { }
|
||||
|
||||
MultiThink(std::uint64_t seed) : prng(seed), loop_count(0) { }
|
||||
|
||||
MultiThink(const std::string& seed) : prng(seed), loop_count(0) { }
|
||||
|
||||
// Call this function from the master thread, each thread will think,
|
||||
// Return control when the thought ending condition is satisfied.
|
||||
// Do something else.
|
||||
// ・It is safe for each thread to call Learner::search(),qsearch()
|
||||
// Separates the substitution table for each thread. (It will be restored after the end.)
|
||||
// ・Book is not thread safe when in on the fly mode, so temporarily change this mode.
|
||||
// Turn it off.
|
||||
// [Requirements]
|
||||
// 1) Override thread_worker()
|
||||
// 2) Set the loop count with set_loop_max()
|
||||
// 3) set a function to be called back periodically (if necessary)
|
||||
// callback_func and callback_interval
|
||||
void go_think();
|
||||
|
||||
// If there is something you want to initialize on the derived class side, override this,
|
||||
// Called when initialization is completed with go_think().
|
||||
// It is better to read the fixed trace at that timing.
|
||||
virtual void init() {}
|
||||
|
||||
// A thread worker that is called by creating a thread when you go_think()
|
||||
// Override and use this.
|
||||
virtual void thread_worker(size_t thread_id) = 0;
|
||||
|
||||
// Called back every callback_seconds [seconds] when go_think().
|
||||
std::function<void()> callback_func;
|
||||
uint64_t callback_seconds = 600;
|
||||
|
||||
// Set the number of times worker processes (calls Search::think()).
|
||||
void set_loop_max(uint64_t loop_max_) { loop_max = loop_max_; }
|
||||
|
||||
// Get the value set by set_loop_max().
|
||||
uint64_t get_loop_max() const { return loop_max; }
|
||||
|
||||
// [ASYNC] Take the value of the loop counter and add the loop counter after taking it out.
|
||||
// If the loop counter has reached loop_max, return UINT64_MAX.
|
||||
// If you want to generate a phase, you must call this function at the time of generating the phase,
|
||||
// Please note that the number of generated phases and the value of the counter will not match.
|
||||
uint64_t get_next_loop_count() {
|
||||
std::unique_lock<std::mutex> lk(loop_mutex);
|
||||
if (loop_count >= loop_max)
|
||||
return LOOP_COUNT_FINISHED;
|
||||
return loop_count++;
|
||||
}
|
||||
|
||||
// [ASYNC] For returning the processed number. Each time it is called, it returns a counter that is incremented.
|
||||
uint64_t get_done_count() {
|
||||
std::unique_lock<std::mutex> lk(loop_mutex);
|
||||
return ++done_count;
|
||||
}
|
||||
|
||||
// Mutex when worker thread accesses I/O
|
||||
std::mutex io_mutex;
|
||||
|
||||
protected:
|
||||
// Random number generator body
|
||||
AsyncPRNG prng;
|
||||
|
||||
private:
|
||||
// number of times worker processes (calls Search::think())
|
||||
std::atomic<uint64_t> loop_max;
|
||||
// number of times the worker has processed (calls Search::think())
|
||||
std::atomic<uint64_t> loop_count;
|
||||
// To return the number of times it has been processed.
|
||||
std::atomic<uint64_t> done_count;
|
||||
|
||||
// Mutex when changing the variables in ↑
|
||||
std::mutex loop_mutex;
|
||||
|
||||
// Thread end flag.
|
||||
std::atomic<uint64_t> threads_finished;
|
||||
};
|
||||
|
||||
// Mechanism to process task during idle time.
|
||||
// master passes the task with push_task_async() whenever you like.
|
||||
// When slave executes on_idle() in its spare time, it retrieves one task and continues execution until there is no queue.
|
||||
// Convenient to use when you want to write MultiThink thread worker in master-slave method.
|
||||
struct TaskDispatcher
|
||||
{
|
||||
typedef std::function<void(size_t /* thread_id */)> Task;
|
||||
|
||||
// slave calls this function during idle.
|
||||
void on_idle(size_t thread_id)
|
||||
{
|
||||
Task task;
|
||||
while ((task = get_task_async()) != nullptr)
|
||||
task(thread_id);
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
// Stack [ASYNC] task.
|
||||
void push_task_async(Task task)
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(task_mutex);
|
||||
tasks.push_back(task);
|
||||
}
|
||||
|
||||
// Allocate size array elements for task in advance.
|
||||
void task_reserve(size_t size)
|
||||
{
|
||||
tasks.reserve(size);
|
||||
}
|
||||
|
||||
protected:
|
||||
// set of tasks
|
||||
std::vector<Task> tasks;
|
||||
|
||||
// Take out one [ASYNC] task. Called from on_idle().
|
||||
Task get_task_async()
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(task_mutex);
|
||||
if (tasks.size() == 0)
|
||||
return nullptr;
|
||||
Task task = *tasks.rbegin();
|
||||
tasks.pop_back();
|
||||
return task;
|
||||
}
|
||||
|
||||
// a mutex for accessing tasks
|
||||
std::mutex task_mutex;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user