{"id":560,"date":"2019-08-04T21:10:42","date_gmt":"2019-08-05T04:10:42","guid":{"rendered":"http:\/\/35.243.195.209\/?p=560"},"modified":"2019-08-04T21:12:21","modified_gmt":"2019-08-05T04:12:21","slug":"thread-pool-in-c","status":"publish","type":"post","link":"https:\/\/nanzhou.cc\/index.php\/2019\/08\/04\/thread-pool-in-c\/","title":{"rendered":"Thread Pool in C++"},"content":{"rendered":"<h2>Summary<\/h2>\n<p>In this post, I will introduce how to build a simple thread pool in C++. <\/p>\n<h2>Conclusion<\/h2>\n<p>The codes are from <a href=\"http:\/\/progsch.net\/wordpress\/?p=81\">here<\/a>. The thread pool only uses <code>thread<\/code>, <code>mutex<\/code>, and <code>condition_variable<\/code>. <\/p>\n<pre><code class=\"language-c++\">#include &lt;thread&gt;\n#include &lt;mutex&gt;\n#include &lt;condition_variable&gt;\n\nclass ThreadPool;\n\n\/\/ our worker thread objects\nclass Worker {\npublic:\n    Worker(ThreadPool &amp;s) : pool(s) { }\n    void operator()();\nprivate:\n    ThreadPool &amp;pool;\n};\n\n\/\/ the actual thread pool\nclass ThreadPool {\npublic:\n    ThreadPool(size_t);\n    template&lt;class F&gt;\n    void enqueue(F f);\n    ~ThreadPool();\nprivate:\n    friend class Worker;\n\n    \/\/ need to keep track of threads so we can join them\n    std::vector&lt; std::thread &gt; workers;\n\n    \/\/ the task queue\n    std::queue&lt; std::function&lt;void()&gt; &gt; tasks;\n\n    \/\/ synchronization\n    std::mutex queue_mutex;\n    std::condition_variable condition;\n    bool stop;\n};\n\nvoid Worker::operator()()\n{\n    std::function&lt;void()&gt; task;\n    while(true)\n    {\n        {   \/\/ acquire lock\n            std::unique_lock&lt;std::mutex&gt;\n                    lock(pool.queue_mutex);\n\n            \/\/ look for a work item\n            while(!pool.stop)\n            { \/\/ if there are none wait for notification\n                pool.condition.wait(lock);\n            }\n\n            if(pool.stop &amp;&amp; pool.tasks.empty()) \/\/ exit if the pool is stopped\n                return;\n\n            \/\/ get the task from the queue\n            task = pool.tasks.front();\n            pool.tasks.pop();\n\n        }   \/\/ release lock\n\n        \/\/ execute the task\n        task();\n    }\n}\n\n\/\/ the constructor just launches some amount of workers\nThreadPool::ThreadPool(size_t threads)\n        :   stop(false)\n{\n    for(size_t i = 0;i&lt;threads;++i) {\n        workers.push_back(std::thread(Worker(*this)));\n    }\n}\n\n\/\/ the destructor joins all threads\nThreadPool::~ThreadPool()\n{\n    \/\/ stop all threads\n    stop = true;\n    condition.notify_all();\n\n    \/\/ join them\n    for(size_t i = 0;i&lt;workers.size();++i)\n        workers[i].join();\n}\n\n\/\/ add new work item to the pool\ntemplate&lt;class F&gt;\nvoid ThreadPool::enqueue(F f)\n{\n    { \/\/ acquire lock\n        std::unique_lock&lt;std::mutex&gt; lock(queue_mutex);\n\n        \/\/ add the task\n        tasks.push(std::function&lt;void()&gt;(f));\n    } \/\/ release lock\n\n    \/\/ wake up one thread\n    condition.notify_one();\n}<\/code><\/pre>\n<h2>Details<\/h2>\n<p>I add some comments in the original codes. Please be compliant with the original license in <a href=\"http:\/\/progsch.net\/wordpress\/?p=81\">the post<\/a>. An improved version is available <a href=\"https:\/\/github.com\/progschj\/ThreadPool\/blob\/master\/ThreadPool.h\">here<\/a>.<\/p>\n<p>I present some related techniques. <\/p>\n<h3>1. condition_variable with predicate<\/h3>\n<p>In <a href=\"http:\/\/35.243.195.209\/index.php\/2019\/08\/04\/mutex-in-c-and-java\/\">this post<\/a>, I introduce the <code>mutex<\/code>, <code>unique_lock<\/code>, and <code>condition_variable<\/code> in C++. I mentioned that <code>condition_variable<\/code> may encounter  <strong>spurious wake-up calls<\/strong>. The predicate aims to avoid these spurious wake-up calls. <\/p>\n<ol>\n<li>The function only blocks if pred returns false; <\/li>\n<li>Notifications can only unblock the thread when it becomes true;<\/li>\n<\/ol>\n<pre><code class=\"language-cpp\">\/\/ the two are equivalent\ncv.wait(lck, [count](){ return count == 0;});\n\nwhile (count != 0) wait(lck);<\/code><\/pre>\n<h3>2. &quot;Capturing&quot; variables in Lambda functions<\/h3>\n<p>You can capture by both reference and value, which you can specify using &amp; and = respectively:<\/p>\n<ol>\n<li>[&amp;epsilon] capture epsilon by reference<\/li>\n<li>[&amp;] captures all variables used in the lambda by reference<\/li>\n<li>[=] captures all variables used in the lambda by value<\/li>\n<li>[&amp;, epsilon] captures variables like with [&amp;], but epsilon by value<\/li>\n<li>[=, &amp;epsilon] captures variables like with [=], but epsilon by reference<\/li>\n<li>[this] simple by-reference capture of the current object<\/li>\n<li>[*this] simple by-copy capture of the current object<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>Summary In this post, I will introduce how to build a simple thread pool in C++. Conclusion The codes are from here. The thread pool only uses thread, mutex, and condition_variable. #include &lt;thread&gt; #include &lt;mutex&gt; #include &lt;condition_variable&gt; class ThreadPool; \/\/ our worker thread objects class Worker { public: Worker(ThreadPool &amp;s) : pool(s) { } void&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,32,31,5],"tags":[],"class_list":["post-560","post","type-post","status-publish","format-standard","hentry","category-c","category-muitl-thread","category-parallel-computation","category-proglang"],"_links":{"self":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts\/560","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/comments?post=560"}],"version-history":[{"count":3,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts\/560\/revisions"}],"predecessor-version":[{"id":563,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts\/560\/revisions\/563"}],"wp:attachment":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/media?parent=560"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/categories?post=560"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/tags?post=560"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}