Code
#include "tbb/concurrent_queue.h"
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
class Logger
{
public:
static void log(const std::string& msg)
{
static std::mutex logMutex;
std::lock_guard<std::mutex> lock(logMutex);
std::cout << msg << std::endl;
}
};
class PiCalculator
{
public:
PiCalculator()
: m_stopRequested(false), m_cv_mutex(), m_queue(), m_condVar(),
m_calcCount(0), m_worker(std::thread([this](){run();})) {}
~PiCalculator()
{
if (m_worker.joinable())
{
requestStop();
m_worker.join();
}
}
void addCalculation(uint64_t iter)
{
m_queue.push(iter);
m_condVar.notify_all();
}
private:
void requestStop()
{
m_stopRequested = true;
m_condVar.notify_all();
}
void run()
{
uint64_t iter = 0;
uint32_t calcNum = 0;
// Worker thread - Gets work from the task queue
while (!m_stopRequested)
{
std::unique_lock<std::mutex> cv_lock(m_cv_mutex);
m_condVar.wait(cv_lock, [this] {
return m_stopRequested || !m_queue.empty();
});
if (!m_stopRequested && m_queue.try_pop(iter))
{
calcNum = m_calcCount++;
calculate(iter, calcNum);
}
}
}
void calculate(uint64_t iter, uint32_t calcNum)
{
// Worker thread - Executes a possibly long time task
auto calcNumStr = std::to_string(calcNum);
Logger::log("[" + calcNumStr + "]" + " Start calculation ...");
double sum = 0.0;
int32_t sign = 1;
for (uint64_t i = 0; !m_stopRequested && i < iter; ++i)
{
sum += sign / (2.0 * i + 1.0);
sign *= -1;
}
auto piStr = std::to_string(4.0 * sum);
Logger::log("[" + calcNumStr + "]" + " ... finished: " + piStr);
}
private:
std::atomic<bool> m_stopRequested;
tbb::concurrent_queue<uint64_t> m_queue;
std::mutex m_cv_mutex;
std::condition_variable m_condVar;
std::atomic<uint32_t> m_calcCount;
std::thread m_worker;
};
int main()
{
// Main thread - Sets up the program
Logger::log("Calculating Pi with the Taylor method");
Logger::log("");
Logger::log("Possible Input:");
Logger::log("- <num> ... number of iterations");
Logger::log("- quit ... quits the process");
Logger::log("");
std::string input = "";
PiCalculator piCalculator;
// Main thread - Enters the main event loop
while (true)
{
std::cin >> input;
if (input == "quit") { break; }
try
{
uint64_t iter = std::stoull(input);
piCalculator.addCalculation(iter);
}
catch (...)
{
Logger::log("The input was invalid");
}
}
return 0;
}
$ g++ main.cpp -ltbb -lpthread
Future
- Switch to a thread pool to execute the different calculations in parallel.