{"id":825,"date":"2019-05-25T16:05:01","date_gmt":"2019-05-25T16:05:01","guid":{"rendered":"https:\/\/blog.afach.de\/?p=825"},"modified":"2019-05-25T16:12:30","modified_gmt":"2019-05-25T16:12:30","slug":"a-simple-lock-free-object-pool","status":"publish","type":"post","link":"https:\/\/blog.afach.de\/?p=825","title":{"rendered":"A simple, lock-free object-pool"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p>Recently, I was using <a href=\"https:\/\/thrift.apache.org\/\">Apache Thrift<\/a> for a distributed high performance C++ application. Apache Thrift is an <a href=\"https:\/\/en.wikipedia.org\/wiki\/Remote_procedure_call\">RPC<\/a> for calling functions on other ends of networks and across different languages. On a single thread, using an RPC is a bad idea, if performance is the goal. So the way to get high performance from such a system is by putting multiple clients in many threads. However, the problem is that Apache Thrift&#8217;s clients are not thread-safe! What do we do?<\/p>\n\n\n\n<p>The solution is an object pool of clients, and since the application is a high-performance, I chose it to be a lock-free object pool. Lock-free means that no mutexes are involved in the design, but only atomic variables. I couldn&#8217;t find anything out there, so I implemented my own, which I hope will be useful to others, too. While this design is lock-free, it&#8217;s not &#8220;wait-free&#8221;. Meaning that, obviously, if all objects in the pool are used, the system will block\/wait until an object is available, or the programmer has to setup an asynchronous waiting mechanism. It&#8217;s possible to &#8220;try&#8221; to get an object in this design.<\/p>\n\n\n\n<p>In the following I&#8217;ll discuss my design of this object pool.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The design<\/h2>\n\n\n\n<p>The design of this object pool is simple. <\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>There&#8217;s a vector of size N that holds N initialized objects. The initialization of the objects is done in the constructor, by passing a functor\/lambda that intializes every object and puts them in the vector (hence, the objects must be at least move-constructible).<\/li><li>I used a lock-free queue from boost. The queue has integers ranging from 0 to N-1. In order to check whether an object is available, its index in the vector has to be in this queue.<\/li><li>If borrowing is successful, a new object &#8220;<code>BorrowedObject<\/code>&#8221; will be returned, which contains a pointer to the borrows object. This is a safe mechanism, where returning to the pool is done automatically when this object is destroyed.<\/li><\/ul>\n\n\n\n<p>Shall we look at some code?<\/p>\n\n\n\n<pre class=\"cpp\"><code class=\"cpp\">template &lt;typename T>\nclass ObjectPool\n{\n    AvailableObjectsQueueType availableObjectsQueue;\n    std::size_t               objectCount;\n    std::vector&lt;T>            objects;\n    std::atomic_uint64_t      availableObjectsCount;\n    std::atomic_bool          shutdownFlag;\n\npublic:\n    friend BorrowedObject&lt;T>;\n    ObjectPool(std::size_t Size, std::function&lt;T(std::size_t)> objectInitializers);\n    ObjectPool()                  = delete;\n    ObjectPool(const ObjectPool&amp;) = delete;\n    ObjectPool(ObjectPool&amp;&amp;)      = delete;\n    ObjectPool&amp; operator=(const ObjectPool&amp;) = delete;\n    ObjectPool&amp; operator=(ObjectPool&amp;&amp;) = delete;\n\n    BorrowedObject&lt;T> borrowObj(uint64_t sleepTime_ms = 0);\n    BorrowedObject&lt;T> try_borrowObj(bool&amp; success);\n    std::size_t       size() const;\n    uint64_t    getAvailableObjectsCount() const;\n    std::vector&lt;T>&amp;   getInternalObjects_unsafe();\n    void              shutdown();\n    ~ObjectPool();\n};<\/code><\/pre>\n\n\n\n<p>As you can see, the class is not copyable or movable, for simplicity. Besdies that, the following methods can be seen:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>The constructor: Takes the size of the pool, and a functor\/lambda to initialize the objects. The parameter in this functor\/lambda is of type <code>std::size_t<\/code>. The purpose of this is to be able to have the initialization done as a function of the number of the object in the pool.<\/li><li><code>borrowObj()<\/code>: A blocking method for borrowing an object from the pool.<\/li><li><code>try_borrowObj()<\/code>: A non-blocking method for borrowing an object from a the pool, returns a null object on failure.<\/li><li><code>shutdown()<\/code>: Shutdown the object pool, which calls the destructor of all objects and prevents borrowing further.<\/li><\/ul>\n\n\n\n<p><a href=\"https:\/\/git.afach.de\/samerafach\/objectpool\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\">You can find the full implementation here.<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Here&#8217;s a simple design of a lock-free object pool. No more than 200 lines. The feature I find cool in this object pool is that the objects themselves are not being passed around, but only their indices, which can be done quite efficiently on most modern CPUs.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Recently, I was using Apache Thrift for a distributed high performance C++ application. Apache Thrift is an RPC for calling functions on other ends of networks and across different languages. On a single thread, using an RPC is a bad idea, if performance is the goal. So the way to get high performance from &hellip; <a href=\"https:\/\/blog.afach.de\/?p=825\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">A simple, lock-free object-pool<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[1],"tags":[18,20,23,25,24,22,21],"class_list":["post-825","post","type-post","status-publish","format-standard","hentry","category-miscillaneous","tag-c","tag-c11","tag-object","tag-object-pool","tag-pool","tag-thread-safe","tag-thread-safety"],"_links":{"self":[{"href":"https:\/\/blog.afach.de\/index.php?rest_route=\/wp\/v2\/posts\/825","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.afach.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.afach.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.afach.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.afach.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=825"}],"version-history":[{"count":10,"href":"https:\/\/blog.afach.de\/index.php?rest_route=\/wp\/v2\/posts\/825\/revisions"}],"predecessor-version":[{"id":836,"href":"https:\/\/blog.afach.de\/index.php?rest_route=\/wp\/v2\/posts\/825\/revisions\/836"}],"wp:attachment":[{"href":"https:\/\/blog.afach.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=825"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.afach.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=825"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.afach.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=825"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}