change rk4 integrator to take vector of doubles, spin off Qt gui in separate thread
This commit is contained in:
		
							parent
							
								
									1b855b2997
								
							
						
					
					
						commit
						90e5289609
					
				@ -83,24 +83,24 @@ void MainWindow::on_testButton2_clicked()
 | 
			
		||||
   double ts = 0.01;
 | 
			
		||||
 | 
			
		||||
   // X position/velocity. x[0] is X position, x[1] is X velocity
 | 
			
		||||
   double x[2] = {0.0, initialVelocityX};
 | 
			
		||||
   std::vector<double> x = {0.0, initialVelocityX};
 | 
			
		||||
 | 
			
		||||
   // Y position/velocity. y[0] is Y position, y[1] is Y velocity
 | 
			
		||||
   double y[2] = {0.0, initialVelocityY};
 | 
			
		||||
   std::vector<double> y = {0.0, initialVelocityY};
 | 
			
		||||
 | 
			
		||||
   auto xvelODE = [mass, dragCoeff](double, double* x) -> double
 | 
			
		||||
   auto xvelODE = [mass, dragCoeff](double, const std::vector<double>& x) -> double
 | 
			
		||||
      {
 | 
			
		||||
 | 
			
		||||
         return -dragCoeff * 1.225 * 0.00774192 / (2.0 * mass) * x[1]*x[1]; };
 | 
			
		||||
   auto xposODE = [](double, double* x) -> double { return x[1]; };
 | 
			
		||||
   auto xposODE = [](double, const std::vector<double>& x) -> double { return x[1]; };
 | 
			
		||||
   sim::RK4Solver xSolver(xposODE, xvelODE);
 | 
			
		||||
   xSolver.setTimeStep(0.01);
 | 
			
		||||
 | 
			
		||||
   auto yvelODE = [mass, dragCoeff](double, double* y) -> double
 | 
			
		||||
   auto yvelODE = [mass, dragCoeff](double, const std::vector<double>& y) -> double
 | 
			
		||||
      {
 | 
			
		||||
 | 
			
		||||
         return -dragCoeff * 1.225 * 0.00774192 / (2.0 * mass) * y[1]*y[1] - 9.8; };
 | 
			
		||||
   auto yposODE = [](double, double* y) -> double { return y[1]; };
 | 
			
		||||
   auto yposODE = [](double, const std::vector<double>& y) -> double { return y[1]; };
 | 
			
		||||
   sim::RK4Solver ySolver(yposODE, yvelODE);
 | 
			
		||||
   ySolver.setTimeStep(0.01);
 | 
			
		||||
 | 
			
		||||
@ -110,18 +110,16 @@ void MainWindow::on_testButton2_clicked()
 | 
			
		||||
   QTextStream cout(stdout);
 | 
			
		||||
   cout << "Initial X velocity: " << initialVelocityX << "\n";
 | 
			
		||||
   cout << "Initial Y velocity: " << initialVelocityY << "\n";
 | 
			
		||||
   double resX[2];
 | 
			
		||||
   double resY[2];
 | 
			
		||||
   std::vector<double> resX(2);
 | 
			
		||||
   std::vector<double> resY(2);
 | 
			
		||||
   for(size_t i = 0; i < maxTs; ++i)
 | 
			
		||||
   {
 | 
			
		||||
      xSolver.step(i * ts, x, resX);
 | 
			
		||||
      ySolver.step(i * ts, y, resY);
 | 
			
		||||
      position.emplace_back(resX[0], resY[0], 0.0);
 | 
			
		||||
 | 
			
		||||
      x[0] = resX[0];
 | 
			
		||||
      x[1] = resX[1];
 | 
			
		||||
      y[0] = resY[0];
 | 
			
		||||
      y[1] = resY[1];
 | 
			
		||||
      x = resX;
 | 
			
		||||
      y = resY;
 | 
			
		||||
 | 
			
		||||
      cout << "(" << position[i].getX1() << ", " << position[i].getX2() << ")\n";
 | 
			
		||||
      if(y[0] < 0.0)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										38
									
								
								main.cpp
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								main.cpp
									
									
									
									
									
								
							@ -4,7 +4,9 @@
 | 
			
		||||
#include <QLocale>
 | 
			
		||||
#include <QTranslator>
 | 
			
		||||
 | 
			
		||||
int main(int argc, char *argv[])
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
void worker(int argc, char* argv[], int& ret)
 | 
			
		||||
{
 | 
			
		||||
   QApplication a(argc, argv);
 | 
			
		||||
   a.setWindowIcon(QIcon(":/qtrocket.png"));
 | 
			
		||||
@ -26,5 +28,37 @@ int main(int argc, char *argv[])
 | 
			
		||||
   // Go!
 | 
			
		||||
   MainWindow w;
 | 
			
		||||
   w.show();
 | 
			
		||||
   return a.exec();
 | 
			
		||||
   ret = a.exec();
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
   /*
 | 
			
		||||
   QApplication a(argc, argv);
 | 
			
		||||
   a.setWindowIcon(QIcon(":/qtrocket.png"));
 | 
			
		||||
 | 
			
		||||
   // Start translation component.
 | 
			
		||||
   // TODO: Only support US English at the moment. Anyone want to help translate?
 | 
			
		||||
   QTranslator translator;
 | 
			
		||||
   const QStringList uiLanguages = QLocale::system().uiLanguages();
 | 
			
		||||
   for (const QString &locale : uiLanguages)
 | 
			
		||||
   {
 | 
			
		||||
      const QString baseName = "qtrocket_" + QLocale(locale).name();
 | 
			
		||||
      if (translator.load(":/i18n/" + baseName))
 | 
			
		||||
      {
 | 
			
		||||
         a.installTranslator(&translator);
 | 
			
		||||
         break;
 | 
			
		||||
      }
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   // Go!
 | 
			
		||||
   //MainWindow w;
 | 
			
		||||
   //w.show();
 | 
			
		||||
   //return a.exec();
 | 
			
		||||
   */
 | 
			
		||||
   int ret = 0;
 | 
			
		||||
   std::thread guiThread(worker, argc, argv, std::ref(ret));
 | 
			
		||||
   guiThread.join();
 | 
			
		||||
   return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,5 +2,7 @@
 | 
			
		||||
 | 
			
		||||
Rocket::Rocket()
 | 
			
		||||
{
 | 
			
		||||
   propagator.setTimeStep(0.01);
 | 
			
		||||
   //propagator.set
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -59,6 +59,7 @@ HEADERS += \
 | 
			
		||||
    utils/BinMap.h \
 | 
			
		||||
    utils/CurlConnection.h \
 | 
			
		||||
    utils/Logger.h \
 | 
			
		||||
    utils/TSQueue.h \
 | 
			
		||||
    utils/ThreadPool.h \
 | 
			
		||||
    utils/ThrustCurveAPI.h \
 | 
			
		||||
    utils/math/Constants.h \
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,8 @@
 | 
			
		||||
#ifndef SIM_DESOLVER_H
 | 
			
		||||
#define SIM_DESOLVER_H
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
namespace sim
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
@ -11,7 +13,7 @@ public:
 | 
			
		||||
   virtual ~DESolver() {}
 | 
			
		||||
 | 
			
		||||
   virtual void setTimeStep(double ts) = 0;
 | 
			
		||||
   virtual void step(double t, double* curVal, double* res ) = 0;
 | 
			
		||||
   virtual void step(double t, const std::vector<double>& curVal, std::vector<double>& res ) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace sim
 | 
			
		||||
 | 
			
		||||
@ -2,27 +2,56 @@
 | 
			
		||||
 | 
			
		||||
#include "sim/RK4Solver.h"
 | 
			
		||||
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
namespace sim {
 | 
			
		||||
 | 
			
		||||
Propagator::Propagator()
 | 
			
		||||
   : integrator()
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//   solver = std::make_unique<sim::DESolver>(
 | 
			
		||||
//            new(RK4Solver(/* xvel */ [this](double, double* x) -> double { return })))
 | 
			
		||||
 | 
			
		||||
   // This is a little strange, but I have to populate the integrator unique_ptr
 | 
			
		||||
   // with reset. make_unique() doesn't work because the compiler can't seem to
 | 
			
		||||
   // deduce the template parameters correctly, and I don't want to specify them
 | 
			
		||||
   // manually either. RK4Solver constructor is perfectly capable of deducing it's
 | 
			
		||||
   // template types, and it derives from DESolver, so we can just reset the unique_ptr
 | 
			
		||||
   // and pass it a freshly allocated RK4Solver pointer
 | 
			
		||||
 | 
			
		||||
   // The state vector has components of the form: (x, y, z, xdot, ydot, zdot)
 | 
			
		||||
 | 
			
		||||
   integrator = std::make_unique<sim::DESolver>(new RK4Solver(
 | 
			
		||||
      /* dvx/dt */ [this](double, double* ) -> double { return getForceX() / getMass(); },
 | 
			
		||||
      /* dx/dt  */ [this](double, double* s) -> double {return s[3]; },
 | 
			
		||||
      /* dvy/dt */ [this](double, double* ) -> double { return getForceY() / getMass() },
 | 
			
		||||
      /* dy/dt  */ [this](double, double* s) -> double {return s[4]; },
 | 
			
		||||
      /* dvz/dt */ [this](double, double* ) -> double { return getForceZ() / getMass() },
 | 
			
		||||
      /* dz/dt  */ [this](double, double* s) -> double {return s[5]; }));
 | 
			
		||||
   integrator.reset(new RK4Solver(
 | 
			
		||||
      /* dx/dt  */ [](double, const std::vector<double>& s) -> double {return s[3]; },
 | 
			
		||||
      /* dy/dt  */ [](double, const std::vector<double>& s) -> double {return s[4]; },
 | 
			
		||||
      /* dz/dt  */ [](double, const std::vector<double>& s) -> double {return s[5]; },
 | 
			
		||||
      /* dvx/dt */ [this](double, const std::vector<double>& ) -> double { return getForceX() / getMass(); },
 | 
			
		||||
      /* dvy/dt */ [this](double, const std::vector<double>& ) -> double { return getForceY() / getMass(); },
 | 
			
		||||
      /* dvz/dt */ [this](double, const std::vector<double>& ) -> double { return getForceZ() / getMass(); }));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   integrator->setTimeStep(timeStep);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Propagator::~Propagator()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Propagator::runUntilTerminate()
 | 
			
		||||
{
 | 
			
		||||
   while(true)
 | 
			
		||||
   {
 | 
			
		||||
      // nextState gets overwritten
 | 
			
		||||
      integrator->step(currentTime, currentState, nextState);
 | 
			
		||||
      std::swap(currentState, nextState);
 | 
			
		||||
      if(saveStates)
 | 
			
		||||
      {
 | 
			
		||||
         states.push_back(currentState);
 | 
			
		||||
      }
 | 
			
		||||
      if(currentState[1] < 0.0)
 | 
			
		||||
         break;
 | 
			
		||||
 | 
			
		||||
      currentTime += timeStep;
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace sim
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@
 | 
			
		||||
#include "sim/DESolver.h"
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
namespace sim
 | 
			
		||||
{
 | 
			
		||||
@ -12,23 +13,50 @@ class Propagator
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Propagator();
 | 
			
		||||
    ~Propagator();
 | 
			
		||||
 | 
			
		||||
   double getForceX();
 | 
			
		||||
   double getForceY();
 | 
			
		||||
   double getForceZ();
 | 
			
		||||
    void setInitialState(std::vector<double>& initialState)
 | 
			
		||||
    {
 | 
			
		||||
       currentState = initialState;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
   double getTorqueP();
 | 
			
		||||
   double getTorqueQ();
 | 
			
		||||
   double getTorqueR();
 | 
			
		||||
    const std::vector<double>& getCurrentState() const
 | 
			
		||||
    {
 | 
			
		||||
       return currentState;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
   double getMass();
 | 
			
		||||
    void runUntilTerminate();
 | 
			
		||||
 | 
			
		||||
    void retainStates(bool s)
 | 
			
		||||
    {
 | 
			
		||||
       saveStates = s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const std::vector<std::vector<double>>& getStates() const { return states; }
 | 
			
		||||
 | 
			
		||||
    void setTimeStep(double ts) { timeStep = ts; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    double getForceX() { return 0.0; }
 | 
			
		||||
    double getForceY() { return 0.0; }
 | 
			
		||||
    double getForceZ() { return 0.0; }
 | 
			
		||||
 | 
			
		||||
    double getTorqueP() { return 0.0; }
 | 
			
		||||
    double getTorqueQ() { return 0.0; }
 | 
			
		||||
    double getTorqueR() { return 0.0; }
 | 
			
		||||
 | 
			
		||||
   double getMass() { return 0.0; }
 | 
			
		||||
 | 
			
		||||
//private:
 | 
			
		||||
 | 
			
		||||
   std::unique_ptr<sim::DESolver> integrator;
 | 
			
		||||
 | 
			
		||||
   double currentState[6]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
 | 
			
		||||
   double nextState[6]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
 | 
			
		||||
   std::vector<double> currentState{0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
 | 
			
		||||
   std::vector<double> nextState{0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
 | 
			
		||||
   bool saveStates{true};
 | 
			
		||||
   double currentTime{0.0};
 | 
			
		||||
   double timeStep{0.01};
 | 
			
		||||
   std::vector<std::vector<double>> states;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace sim
 | 
			
		||||
 | 
			
		||||
@ -19,13 +19,14 @@ public:
 | 
			
		||||
   RK4Solver(Ts... funcs)
 | 
			
		||||
   {
 | 
			
		||||
      (odes.push_back(funcs), ...);
 | 
			
		||||
      temp.resize(sizeof...(Ts));
 | 
			
		||||
 | 
			
		||||
   }
 | 
			
		||||
   virtual ~RK4Solver() {}
 | 
			
		||||
 | 
			
		||||
   void setTimeStep(double inTs) override { dt = inTs;  halfDT = dt / 2.0; }
 | 
			
		||||
 | 
			
		||||
   void step(double t, double* curVal, double* res) override
 | 
			
		||||
   void step(double t, const std::vector<double>& curVal, std::vector<double>& res) override
 | 
			
		||||
   {
 | 
			
		||||
      if(dt == std::numeric_limits<double>::quiet_NaN())
 | 
			
		||||
      {
 | 
			
		||||
@ -76,7 +77,7 @@ public:
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
   std::vector<std::function<double(double, double*)>> odes;
 | 
			
		||||
   std::vector<std::function<double(double, const std::vector<double>&)>> odes;
 | 
			
		||||
 | 
			
		||||
   static constexpr size_t len = sizeof...(Ts);
 | 
			
		||||
   double k1[len];
 | 
			
		||||
@ -84,7 +85,7 @@ private:
 | 
			
		||||
   double k3[len];
 | 
			
		||||
   double k4[len];
 | 
			
		||||
 | 
			
		||||
   double temp[len];
 | 
			
		||||
   std::vector<double> temp;
 | 
			
		||||
 | 
			
		||||
   double dt = std::numeric_limits<double>::quiet_NaN();
 | 
			
		||||
   double halfDT = 0.0;
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@ class StateData
 | 
			
		||||
public:
 | 
			
		||||
   StateData();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
   math::Vector3 position{0.0, 0.0, 0.0};
 | 
			
		||||
   math::Vector3 velocity{0.0, 0.0, 0.0};
 | 
			
		||||
@ -23,6 +24,8 @@ private:
 | 
			
		||||
   // Necessary?
 | 
			
		||||
   //math::Vector3 orientationAccel;
 | 
			
		||||
 | 
			
		||||
   // This is an array because the integrator expects it
 | 
			
		||||
   double data[6];
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										83
									
								
								utils/TSQueue.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								utils/TSQueue.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,83 @@
 | 
			
		||||
#ifndef TSQUEUE_H
 | 
			
		||||
#define TSQUEUE_H
 | 
			
		||||
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <queue>
 | 
			
		||||
#include <condition_variable>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief The TSQueue class is a very basic thread-safe queue
 | 
			
		||||
 */
 | 
			
		||||
template<typename T>
 | 
			
		||||
class TSQueue
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
   TSQueue()
 | 
			
		||||
      : mtx(),
 | 
			
		||||
        q(),
 | 
			
		||||
        cv()
 | 
			
		||||
   {}
 | 
			
		||||
 | 
			
		||||
   void push(T newVal)
 | 
			
		||||
   {
 | 
			
		||||
      std::lock_guard<std::mutex> lck(mtx);
 | 
			
		||||
      q.push(newVal);
 | 
			
		||||
      cv.notify_one();
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   void waitAndPop(T& val)
 | 
			
		||||
   {
 | 
			
		||||
      std::unique_lock<std::mutex> lck(mtx);
 | 
			
		||||
      cv.wait(lck, [this]{return !q.empty(); });
 | 
			
		||||
      val = std::move(q.front());
 | 
			
		||||
      q.pop();
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   std::shared_ptr<T> waitAndPop()
 | 
			
		||||
   {
 | 
			
		||||
      std::unique_lock<std::mutex> lck(mtx);
 | 
			
		||||
      cv.wait(lck, [this] { return !q.empty(); });
 | 
			
		||||
      std::shared_ptr<T> res(std::make_shared<T>(std::move(q.front())));
 | 
			
		||||
      q.pop();
 | 
			
		||||
      return res;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   bool tryPop(T& val)
 | 
			
		||||
   {
 | 
			
		||||
      std::unique_lock<std::mutex> lck(mtx);
 | 
			
		||||
      if(q.empty())
 | 
			
		||||
      {
 | 
			
		||||
         return false;
 | 
			
		||||
      }
 | 
			
		||||
      val = std::move(q.front());
 | 
			
		||||
      q.pop();
 | 
			
		||||
      return true;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   std::shared_ptr<T> tryPop()
 | 
			
		||||
   {
 | 
			
		||||
      std::unique_lock<std::mutex> lck(mtx);
 | 
			
		||||
      if(q.empty())
 | 
			
		||||
      {
 | 
			
		||||
         return std::shared_ptr<T>(); // nullptr
 | 
			
		||||
      }
 | 
			
		||||
      std::shared_ptr<T> retVal(std::move(q.front()));
 | 
			
		||||
      q.pop();
 | 
			
		||||
      return retVal;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   bool empty() const
 | 
			
		||||
   {
 | 
			
		||||
      std::lock_guard<std::mutex> lck(mtx);
 | 
			
		||||
      return q.empty();
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
   mutable std::mutex mtx;
 | 
			
		||||
   std::queue<T> q;
 | 
			
		||||
   std::condition_variable cv;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // TSQUEUE_H
 | 
			
		||||
@ -1,6 +1,45 @@
 | 
			
		||||
#include "ThreadPool.h"
 | 
			
		||||
 | 
			
		||||
ThreadPool::ThreadPool()
 | 
			
		||||
{
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
ThreadPool::ThreadPool()
 | 
			
		||||
   : done(false),
 | 
			
		||||
     q(),
 | 
			
		||||
     threads(),
 | 
			
		||||
     joiner(threads)
 | 
			
		||||
{
 | 
			
		||||
   const std::size_t threadCount = std::thread::hardware_concurrency();
 | 
			
		||||
 | 
			
		||||
   try
 | 
			
		||||
   {
 | 
			
		||||
      for(size_t i = 0; i < threadCount; ++i)
 | 
			
		||||
      {
 | 
			
		||||
         threads.push_back(std::thread(&ThreadPool::worker, this));
 | 
			
		||||
      }
 | 
			
		||||
   }
 | 
			
		||||
   catch(...)
 | 
			
		||||
   {
 | 
			
		||||
      done = true;
 | 
			
		||||
      throw;
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ThreadPool::~ThreadPool()
 | 
			
		||||
{
 | 
			
		||||
   done = true;
 | 
			
		||||
}
 | 
			
		||||
void ThreadPool::worker()
 | 
			
		||||
{
 | 
			
		||||
   while(!done)
 | 
			
		||||
   {
 | 
			
		||||
      std::function<void()> task;
 | 
			
		||||
      if(q.tryPop(task))
 | 
			
		||||
      {
 | 
			
		||||
         task();
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
         std::this_thread::yield();
 | 
			
		||||
      }
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,12 @@
 | 
			
		||||
#define THREADPOOL_H
 | 
			
		||||
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
#include "TSQueue.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief A basic ThreadPool class
 | 
			
		||||
@ -10,8 +16,46 @@ class ThreadPool
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
   ThreadPool();
 | 
			
		||||
   ~ThreadPool();
 | 
			
		||||
 | 
			
		||||
   template<typename FunctionType>
 | 
			
		||||
   void submit(FunctionType f)
 | 
			
		||||
   {
 | 
			
		||||
      q.push(std::function<void()>(f));
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
   class JoinThreads
 | 
			
		||||
   {
 | 
			
		||||
   public:
 | 
			
		||||
      explicit JoinThreads(std::vector<std::thread>& inThreads)
 | 
			
		||||
         : threads(inThreads)
 | 
			
		||||
      {}
 | 
			
		||||
 | 
			
		||||
      ~JoinThreads()
 | 
			
		||||
      {
 | 
			
		||||
         for(auto& i : threads)
 | 
			
		||||
         {
 | 
			
		||||
            if(i.joinable())
 | 
			
		||||
            {
 | 
			
		||||
               i.join();
 | 
			
		||||
            }
 | 
			
		||||
         }
 | 
			
		||||
      }
 | 
			
		||||
   private:
 | 
			
		||||
      std::vector<std::thread>& threads;
 | 
			
		||||
   };
 | 
			
		||||
 | 
			
		||||
   std::atomic_bool done;
 | 
			
		||||
   TSQueue<std::function<void()>> q;
 | 
			
		||||
   std::vector<std::thread> threads;
 | 
			
		||||
 | 
			
		||||
   JoinThreads joiner;
 | 
			
		||||
 | 
			
		||||
   void worker();
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif // THREADPOOL_H
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user