summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sim.cpp101
-rw-r--r--sim.h39
2 files changed, 139 insertions, 1 deletions
diff --git a/sim.cpp b/sim.cpp
index a5f6558..5215906 100644
--- a/sim.cpp
+++ b/sim.cpp
@@ -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())
diff --git a/sim.h b/sim.h
index ff618ef..6c66121 100644
--- a/sim.h
+++ b/sim.h
@@ -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()