diff options
-rw-r--r-- | sim.cpp | 101 | ||||
-rw-r--r-- | sim.h | 39 |
2 files changed, 139 insertions, 1 deletions
@@ -38,10 +38,12 @@ Simulator::Simulator() : m_logfileIsOpen(false), m_hasHeader(false), m_dispatch(0), m_iterations(0), m_ignoreOppos(false) { m_originalGame.addPosition(); + setThreadCount(2); } Simulator::~Simulator() { + setThreadCount(0); closeLogfile(); } @@ -214,6 +216,42 @@ void Simulator::resetNumbers() m_iterations = 0; } +void Simulator::simThreadFunc(SimmedMoveMessageQueue& incoming, SimmedMoveMessageQueue& outgoing) +{ + while (true) + { + auto result = incoming.pop_or_terminate(); + if (result.second) + break; + Simulator::simulateOnePosition(result.first, incoming.constants()); + outgoing.push(result.first); + } +} + +void Simulator::setThreadCount(size_t count) +{ + if (count == 0 && m_threadPool.size() != 0) + { + m_sendQueue.send_terminate_all(); + for (auto& t : m_threadPool) + t.join(); + m_threadPool.clear(); + } + + while (count > m_threadPool.size()) + { + m_threadPool.emplace_back(Simulator::simThreadFunc, std::ref(m_sendQueue), std::ref(m_receiveQueue)); + } + + while (count < m_threadPool.size()) + { + m_sendQueue.send_terminate_one(m_threadPool.back().get_id()); + m_threadPool.back().join(); + m_threadPool.pop_back(); + } +} + + void Simulator::simulate(int plies, int iterations) { for (int i = 0; i < iterations; ++i) @@ -252,6 +290,8 @@ void Simulator::simulate(int plies) constants.ignoreOppos = m_ignoreOppos; constants.isLogging = isLogging(); + m_sendQueue.setConstants(constants); + if (isLogging()) { if (!m_hasHeader) @@ -261,6 +301,8 @@ void Simulator::simulate(int plies) m_xmlIndent += MARK_UV('\t'); } + int messageCount = 0; + for (auto &moveIt : m_simmedMoves) { if (!moveIt.includeInSimulation()) @@ -279,7 +321,13 @@ void Simulator::simulate(int plies) message.levels = moveIt.levels; message.xmlIndent = m_xmlIndent; - simulateOnePosition(message, constants); + m_sendQueue.push(message); + messageCount++; + } + + while (messageCount-- > 0) + { + SimmedMoveMessage message(m_receiveQueue.pop()); incorporateMessage(message); } @@ -561,6 +609,57 @@ void AveragedValue::clear() //////////// +void SimmedMoveMessageQueue::push(SimmedMoveMessage& msg) +{ + std::lock_guard<std::mutex> lk(m_queueMutex); + m_queue.push(std::move(msg)); + m_condition.notify_one(); +} + +std::pair<SimmedMoveMessage, bool> SimmedMoveMessageQueue::pop_or_terminate() +{ + std::unique_lock<std::mutex> lk(m_queueMutex); + if (m_queue.empty() && !m_terminateAll && m_terminateOne == std::thread::id()) + m_condition.wait(lk); + std::pair<SimmedMoveMessage, bool> result; + result.second = m_terminateAll || m_terminateOne == std::this_thread::get_id(); + if (result.second) + m_terminateOne = std::thread::id(); + else + { + result.first = std::move(m_queue.front()); + m_queue.pop(); + } + return result; +} + +SimmedMoveMessage SimmedMoveMessageQueue::pop() +{ + std::unique_lock<std::mutex> lk(m_queueMutex); + if (m_queue.empty()) + m_condition.wait(lk); + SimmedMoveMessage result = std::move(m_queue.front()); + m_queue.pop(); + return result; +} + +void SimmedMoveMessageQueue::send_terminate_all() +{ + std::lock_guard<std::mutex> lk(m_queueMutex); + m_terminateAll = true; + m_condition.notify_all(); +} + +void SimmedMoveMessageQueue::send_terminate_one(const std::thread::id& id) +{ + std::lock_guard<std::mutex> lk(m_queueMutex); + m_terminateOne = id; + m_condition.notify_all(); +} + + +//////////// + double SimmedMove::calculateEquity() const { if (levels.empty()) @@ -20,7 +20,11 @@ #define QUACKLE_SIM_H #include <atomic> +#include <condition_variable> +#include <mutex> +#include <queue> #include <sstream> +#include <thread> #include <vector> #include "alphabetparameters.h" @@ -201,11 +205,38 @@ public: bool isLogging; }; +class SimmedMoveMessageQueue +{ +public: + SimmedMoveMessageQueue() = default; + SimmedMoveMessageQueue(SimmedMoveMessageQueue&) = delete; + SimmedMoveMessageQueue(SimmedMoveMessageQueue&&) = delete; + + void push(SimmedMoveMessage& msg); + SimmedMoveMessage pop(); + std::pair<SimmedMoveMessage, bool> pop_or_terminate(); + void send_terminate_all(); + void send_terminate_one(const std::thread::id& id); + + const SimmedMoveConstants& constants() { return m_constants; }; + void setConstants(const SimmedMoveConstants& constants) { m_constants = constants; }; + +private: + SimmedMoveConstants m_constants; + std::queue<SimmedMoveMessage> m_queue; + std::condition_variable m_condition; + std::mutex m_queueMutex; + bool m_terminateAll = false; + std::thread::id m_terminateOne; +}; + class Simulator { public: // constructs a new simulator Simulator(); + Simulator(const Simulator&) = delete; + Simulator(Simulator&&) = delete; ~Simulator(); // Simulate moves on this position. Also initializes the @@ -263,6 +294,9 @@ public: void setIgnoreOppos(bool ignore); bool ignoreOppos() const; + static void simThreadFunc(SimmedMoveMessageQueue& incoming, SimmedMoveMessageQueue& outgoing); + void setThreadCount(size_t count); + // set values for all levels of all moves to zero void resetNumbers(); @@ -337,6 +371,11 @@ protected: int m_iterations; bool m_ignoreOppos; + + // Pair of thread and bool requesting to terminate + std::vector<std::thread> m_threadPool; + SimmedMoveMessageQueue m_sendQueue; + SimmedMoveMessageQueue m_receiveQueue; }; inline GamePosition &Simulator::currentPosition() |