{"id":19002,"date":"2025-08-12T09:56:12","date_gmt":"2025-08-12T09:56:12","guid":{"rendered":"http:\/\/www.max-sperling.bplaced.net\/?p=19002"},"modified":"2025-08-14T16:45:16","modified_gmt":"2025-08-14T16:45:16","slug":"threading-example-with-passive-waiting-c","status":"publish","type":"post","link":"http:\/\/www.max-sperling.bplaced.net\/?p=19002","title":{"rendered":"Threaded pi calculation with concurrent queue (C++)"},"content":{"rendered":"<h2>Code<\/h2>\n<pre class=\"brush: cpp; gutter: false; title: ; notranslate\" title=\"\">\r\n#include &quot;tbb\/concurrent_queue.h&quot;\r\n\r\n#include &lt;atomic&gt;\r\n#include &lt;condition_variable&gt;\r\n#include &lt;iostream&gt;\r\n#include &lt;mutex&gt;\r\n#include &lt;thread&gt;\r\n\r\nclass Logger\r\n{\r\npublic:\r\n    static void log(const std::string&amp; msg)\r\n    {\r\n        static std::mutex logMutex;\r\n        std::lock_guard&lt;std::mutex&gt; lock(logMutex);\r\n        std::cout &lt;&lt; msg &lt;&lt; std::endl;\r\n    }\r\n};\r\n\r\nclass PiCalculator\r\n{\r\npublic:\r\n    PiCalculator()\r\n    : m_stopRequested(false), m_cv_mutex(), m_queue(), m_condVar(),\r\n      m_calcCount(0), m_worker(std::thread([this](){run();})) {}\r\n\r\n    ~PiCalculator()\r\n    {\r\n        if (m_worker.joinable())\r\n        {\r\n            requestStop();\r\n            m_worker.join();\r\n        }\r\n    }\r\n\r\n    void addCalculation(uint64_t iter)\r\n    {\r\n        m_queue.push(iter);\r\n        m_condVar.notify_all();\r\n    }\r\n\r\nprivate:\r\n    void requestStop()\r\n    {\r\n        m_stopRequested = true;\r\n        m_condVar.notify_all();\r\n    }\r\n\r\n    void run()\r\n    {\r\n        uint64_t iter = 0;\r\n        uint32_t calcNum = 0;\r\n\r\n        \/\/ Worker thread - Gets work from the task queue\r\n\r\n        while (!m_stopRequested)\r\n        {\r\n            std::unique_lock&lt;std::mutex&gt; cv_lock(m_cv_mutex);\r\n            m_condVar.wait(cv_lock, [this] {\r\n                return m_stopRequested || !m_queue.empty();\r\n            });\r\n\r\n            if (!m_stopRequested &amp;&amp; m_queue.try_pop(iter))\r\n            {\r\n                calcNum = m_calcCount++;\r\n                calculate(iter, calcNum);\r\n            }\r\n        }\r\n    }\r\n\r\n    void calculate(uint64_t iter, uint32_t calcNum)\r\n    {\r\n        \/\/ Worker thread - Executes a possibly long time task\r\n\r\n        auto calcNumStr = std::to_string(calcNum);\r\n        Logger::log(&quot;[&quot; + calcNumStr + &quot;]&quot; + &quot; Start calculation ...&quot;);\r\n\r\n        double sum = 0.0;\r\n        int32_t sign = 1;\r\n\r\n        for (uint64_t i = 0; !m_stopRequested &amp;&amp; i &lt; iter; ++i)\r\n        {\r\n            sum += sign \/ (2.0 * i + 1.0);\r\n            sign *= -1;\r\n        }\r\n\r\n        auto piStr = std::to_string(4.0 * sum);\r\n        Logger::log(&quot;[&quot; + calcNumStr + &quot;]&quot; + &quot; ... finished: &quot; + piStr);\r\n    }\r\n\r\nprivate:\r\n    std::atomic&lt;bool&gt; m_stopRequested;\r\n    tbb::concurrent_queue&lt;uint64_t&gt; m_queue;\r\n    std::mutex m_cv_mutex;\r\n    std::condition_variable m_condVar;\r\n    std::atomic&lt;uint32_t&gt; m_calcCount;\r\n    std::thread m_worker;\r\n};\r\n\r\nint main()\r\n{\r\n    \/\/ Main thread - Sets up the program\r\n\r\n    Logger::log(&quot;Calculating Pi with the Taylor method&quot;);\r\n    Logger::log(&quot;&quot;);\r\n    Logger::log(&quot;Possible Input:&quot;);\r\n    Logger::log(&quot;- &lt;num&gt; ... number of iterations&quot;);\r\n    Logger::log(&quot;- quit  ... quits the process&quot;);\r\n    Logger::log(&quot;&quot;);\r\n\r\n    std::string input = &quot;&quot;;\r\n    PiCalculator piCalculator;\r\n\r\n    \/\/ Main thread - Enters the main event loop\r\n\r\n    while (true)\r\n    {\r\n        std::cin &gt;&gt; input;\r\n\r\n        if (input == &quot;quit&quot;) { break; }\r\n\r\n        try\r\n        {\r\n            uint64_t iter = std::stoull(input);\r\n            piCalculator.addCalculation(iter);\r\n        }\r\n        catch (...)\r\n        {\r\n            Logger::log(&quot;The input was invalid&quot;);\r\n        }\r\n    }\r\n\r\n    return 0;\r\n}\r\n<\/pre>\n<pre>\r\n$ g++ main.cpp -ltbb -lpthread\r\n<\/pre>\n<hr>\n<h2>Future<\/h2>\n<ul>\n<li>Switch to a thread pool to execute the different calculations in parallel.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Code $ g++ main.cpp -ltbb -lpthread Future Switch to a thread pool to execute the different calculations in parallel.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false},"categories":[63],"tags":[],"_links":{"self":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts\/19002"}],"collection":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=19002"}],"version-history":[{"count":4,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts\/19002\/revisions"}],"predecessor-version":[{"id":19037,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts\/19002\/revisions\/19037"}],"wp:attachment":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=19002"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=19002"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=19002"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}