{"id":10666,"date":"2025-02-24T11:58:47","date_gmt":"2025-02-24T11:58:47","guid":{"rendered":"https:\/\/www.modernescpp.com\/?p=10666"},"modified":"2025-07-03T14:36:46","modified_gmt":"2025-07-03T14:36:46","slug":"a-lock-free-stack-a-simple-garbage-collector","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/a-lock-free-stack-a-simple-garbage-collector\/","title":{"rendered":"A Lock-Free Stack: A Simple Garbage Collector"},"content":{"rendered":"\n<p>My next lock-free stack includes a simple garbage collector.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"711\" height=\"491\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/01\/Time26Concurrency.png\" alt=\"\" class=\"wp-image-10580\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/01\/Time26Concurrency.png 711w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/01\/Time26Concurrency-300x207.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/01\/Time26Concurrency-705x487.png 705w\" sizes=\"auto, (max-width: 711px) 100vw, 711px\" \/><\/figure>\n\n\n\n<p>I discussed the concurrent execution of more than one <code>topAndPush <\/code>call is a Race Condition. I can safely delete a node if not more than one <code>topAndPush <\/code>call is executing concurrently. This observation is crucial for solving this memory leak issue: I store removed nodes on a to-be-deleted list and delete the nodes on this list if no more than one <code>topAndPush <\/code>call is active. There is only one challenge left: How can I be sure that not more than one <code>topAndPush <\/code>call is active? I use an atomic counter that is incremented at the start of <code>topAndPush <\/code>and decremented at its end. The counter is zero or one if no or one <code>topAndPush <\/code>call is active.<\/p>\n\n\n\n<p><br>The following program implements the presented strategy. I use the <code>lockFreeStackWithLeaks.cpp <\/code>from the article &#8220;<a href=\"https:\/\/www.modernescpp.com\/index.php\/a-lock-free-stack-a-complete-implementation\/\">A Lock-Free Stack: A Complete Implementation<\/a>&#8221; as the starting point.<\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\"><span style=\"color: #0099FF; font-style: italic\">\/\/ lockFreeStackWithGarbageCollection.cpp<\/span>\n\n<span style=\"color: #009999\">#include &lt;atomic&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;future&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;stdexcept&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;thread&gt;<\/span>\n\n<span style=\"color: #006699; font-weight: bold\">template<\/span><span style=\"color: #555555\">&lt;<\/span><span style=\"color: #006699; font-weight: bold\">typename<\/span> T<span style=\"color: #555555\">&gt;<\/span>\n<span style=\"color: #006699; font-weight: bold\">class<\/span> <span style=\"color: #00AA88; font-weight: bold\">LockFreeStack<\/span> {\n <span style=\"color: #9999FF\">private:<\/span>\n    <span style=\"color: #006699; font-weight: bold\">struct<\/span> Node {\n        T data;\n        Node<span style=\"color: #555555\">*<\/span> next;\n        Node(T d)<span style=\"color: #555555\">:<\/span> data(d), next(nullptr){ }\n    };\n\n    std<span style=\"color: #555555\">::<\/span>atomic<span style=\"color: #555555\">&lt;<\/span>Node<span style=\"color: #555555\">*&gt;<\/span> head{nullptr};\n    std<span style=\"color: #555555\">::<\/span>atomic<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #007788; font-weight: bold\">int<\/span><span style=\"color: #555555\">&gt;<\/span> topAndPopCounter{};                                            <span style=\"color: #0099FF; font-style: italic\">\/\/ 1<\/span>\n    std<span style=\"color: #555555\">::<\/span>atomic<span style=\"color: #555555\">&lt;<\/span>Node<span style=\"color: #555555\">*&gt;<\/span> toBeDeletedNodes{nullptr};                                   <span style=\"color: #0099FF; font-style: italic\">\/\/ 2<\/span>\n\n    <span style=\"color: #007788; font-weight: bold\">void<\/span> <span style=\"color: #CC00FF\">tryToDelete<\/span>(Node<span style=\"color: #555555\">*<\/span> oldHead) {                                              <span style=\"color: #0099FF; font-style: italic\">\/\/ 3<\/span>\n        <span style=\"color: #006699; font-weight: bold\">if<\/span> (topAndPopCounter  <span style=\"color: #555555\">==<\/span> <span style=\"color: #FF6600\">1<\/span>) {                                              <span style=\"color: #0099FF; font-style: italic\">\/\/ 6<\/span>\n            Node<span style=\"color: #555555\">*<\/span> copyOfToBeDeletedNodes <span style=\"color: #555555\">=<\/span> toBeDeletedNodes.exchange(nullptr);     <span style=\"color: #0099FF; font-style: italic\">\/\/ 8<\/span>\n            <span style=\"color: #006699; font-weight: bold\">if<\/span> (topAndPopCounter <span style=\"color: #555555\">==<\/span> <span style=\"color: #FF6600\">1<\/span>) deleteAllNodes(copyOfToBeDeletedNodes);     <span style=\"color: #0099FF; font-style: italic\">\/\/ 9<\/span>\n            <span style=\"color: #006699; font-weight: bold\">else<\/span> addNodeToBeDeletedNodes(copyOfToBeDeletedNodes); \n            <span style=\"color: #006699; font-weight: bold\">delete<\/span> oldHead;\n        }\n        <span style=\"color: #006699; font-weight: bold\">else<\/span> addNodeToBeDeletedNodes(oldHead);                                     <span style=\"color: #0099FF; font-style: italic\">\/\/ 7<\/span>\n    }\n\n    <span style=\"color: #007788; font-weight: bold\">void<\/span> <span style=\"color: #CC00FF\">addNodeToBeDeletedNodes<\/span>(Node<span style=\"color: #555555\">*<\/span> oldHead) { \n        oldHead<span style=\"color: #555555\">-&gt;<\/span>next <span style=\"color: #555555\">=<\/span> toBeDeletedNodes;\n        <span style=\"color: #006699; font-weight: bold\">while<\/span>( <span style=\"color: #555555\">!<\/span>toBeDeletedNodes.compare_exchange_strong(oldHead<span style=\"color: #555555\">-&gt;<\/span>next, oldHead) ); <span style=\"color: #0099FF; font-style: italic\">\/\/ 10<\/span>\n    }\n\n    <span style=\"color: #007788; font-weight: bold\">void<\/span> <span style=\"color: #CC00FF\">deleteAllNodes<\/span>(Node<span style=\"color: #555555\">*<\/span> currentNode) {                                      <span style=\"color: #0099FF; font-style: italic\">\/\/ 4<\/span>\n        <span style=\"color: #006699; font-weight: bold\">while<\/span> (currentNode) {\n            Node<span style=\"color: #555555\">*<\/span> nextNode <span style=\"color: #555555\">=<\/span> currentNode<span style=\"color: #555555\">-&gt;<\/span>next;\n            <span style=\"color: #006699; font-weight: bold\">delete<\/span> currentNode;\n            currentNode <span style=\"color: #555555\">=<\/span> nextNode;\n        }\n     }\n\n <span style=\"color: #9999FF\">public:<\/span>\n    LockFreeStack() <span style=\"color: #555555\">=<\/span> <span style=\"color: #006699; font-weight: bold\">default<\/span>;\n    LockFreeStack(<span style=\"color: #006699; font-weight: bold\">const<\/span> LockFreeStack<span style=\"color: #555555\">&amp;<\/span>) <span style=\"color: #555555\">=<\/span> <span style=\"color: #006699; font-weight: bold\">delete<\/span>;\n    LockFreeStack<span style=\"color: #555555\">&amp;<\/span> <span style=\"color: #006699; font-weight: bold\">operator<\/span><span style=\"color: #555555\">=<\/span> (<span style=\"color: #006699; font-weight: bold\">const<\/span> LockFreeStack<span style=\"color: #555555\">&amp;<\/span>) <span style=\"color: #555555\">=<\/span> <span style=\"color: #006699; font-weight: bold\">delete<\/span>;\n   \n    <span style=\"color: #007788; font-weight: bold\">void<\/span> <span style=\"color: #CC00FF\">push<\/span>(T val) {\n        Node<span style=\"color: #555555\">*<\/span> <span style=\"color: #006699; font-weight: bold\">const<\/span> newNode <span style=\"color: #555555\">=<\/span> <span style=\"color: #006699; font-weight: bold\">new<\/span> Node(val); \n        newNode<span style=\"color: #555555\">-&gt;<\/span>next <span style=\"color: #555555\">=<\/span> head.load();\n        <span style=\"color: #006699; font-weight: bold\">while<\/span>( <span style=\"color: #555555\">!<\/span>head.compare_exchange_strong(newNode<span style=\"color: #555555\">-&gt;<\/span>next, newNode) );\n    }\n\n    T <span style=\"color: #CC00FF\">topAndPop<\/span>() {\n        <span style=\"color: #555555\">++<\/span>topAndPopCounter;\n        Node<span style=\"color: #555555\">*<\/span> oldHead <span style=\"color: #555555\">=<\/span> head.load();\n        <span style=\"color: #006699; font-weight: bold\">while<\/span>( oldHead <span style=\"color: #555555\">&amp;&amp;<\/span> <span style=\"color: #555555\">!<\/span>head.compare_exchange_strong(oldHead, oldHead<span style=\"color: #555555\">-&gt;<\/span>next) ) {\n            <span style=\"color: #006699; font-weight: bold\">if<\/span> ( <span style=\"color: #555555\">!<\/span>oldHead ) <span style=\"color: #006699; font-weight: bold\">throw<\/span> std<span style=\"color: #555555\">::<\/span>out_of_range(<span style=\"color: #CC3300\">&quot;The stack is empty!&quot;<\/span>);\n        }\n        <span style=\"color: #006699; font-weight: bold\">auto<\/span> topElement <span style=\"color: #555555\">=<\/span> oldHead<span style=\"color: #555555\">-&gt;<\/span>data;\n        tryToDelete(oldHead);                                                   <span style=\"color: #0099FF; font-style: italic\">\/\/ 5<\/span>\n        <span style=\"color: #555555\">--<\/span>topAndPopCounter;\n        <span style=\"color: #006699; font-weight: bold\">return<\/span> topElement;\n    }\n};\n   \n<span style=\"color: #007788; font-weight: bold\">int<\/span> <span style=\"color: #CC00FF\">main<\/span>(){\n\n    LockFreeStack<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #007788; font-weight: bold\">int<\/span><span style=\"color: #555555\">&gt;<\/span> lockFreeStack;\n    \n    <span style=\"color: #006699; font-weight: bold\">auto<\/span> fut <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>async([<span style=\"color: #555555\">&amp;<\/span>lockFreeStack]{ lockFreeStack.push(<span style=\"color: #FF6600\">2011<\/span>); });\n    <span style=\"color: #006699; font-weight: bold\">auto<\/span> fut1 <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>async([<span style=\"color: #555555\">&amp;<\/span>lockFreeStack]{ lockFreeStack.push(<span style=\"color: #FF6600\">2014<\/span>); });\n    <span style=\"color: #006699; font-weight: bold\">auto<\/span> fut2 <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>async([<span style=\"color: #555555\">&amp;<\/span>lockFreeStack]{ lockFreeStack.push(<span style=\"color: #FF6600\">2017<\/span>); });\n    \n    <span style=\"color: #006699; font-weight: bold\">auto<\/span> fut3 <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>async([<span style=\"color: #555555\">&amp;<\/span>lockFreeStack]{ <span style=\"color: #006699; font-weight: bold\">return<\/span> lockFreeStack.topAndPop(); });\n    <span style=\"color: #006699; font-weight: bold\">auto<\/span> fut4 <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>async([<span style=\"color: #555555\">&amp;<\/span>lockFreeStack]{ <span style=\"color: #006699; font-weight: bold\">return<\/span> lockFreeStack.topAndPop(); });\n    <span style=\"color: #006699; font-weight: bold\">auto<\/span> fut5 <span style=\"color: #555555\">=<\/span> std<span style=\"color: #555555\">::<\/span>async([<span style=\"color: #555555\">&amp;<\/span>lockFreeStack]{ <span style=\"color: #006699; font-weight: bold\">return<\/span> lockFreeStack.topAndPop(); });\n    \n    fut.get(), fut1.get(), fut2.get();\n    \n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> fut3.get() <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&#39;\\n&#39;<\/span>;\n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> fut4.get() <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&#39;\\n&#39;<\/span>;\n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> fut5.get() <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&#39;\\n&#39;<\/span>;\n\n}\n<\/pre><\/div>\n\n\n\n<p>The lock-free stack has two new attributes and three new member functions. The atomic counter<br>t<code>opAndPopCounter counts<\/code> (line 1) the number of active <code>topAndPop <\/code>calls, and the atomic pointer <code>toBeDeletedNodes <\/code>(line 2) is a pointer to the list of the to-be-deleted nodes. Additionally, the member function <code>tryToDelete <\/code>(line 3) tries to delete removed nodes. The member function <code>addNodeToBeDeletedNodes <\/code>adds a node to the to-be-deleted list, and the member function <code>deleteAllNodes <\/code>(line 4) deletes all nodes. <\/p>\n\n\n\n<p>Let\u2019s analyze the member function <code>topAndPop<\/code>. At the beginning and the end of <code>topAndPop <\/code>, t<code>opAndPopCounter <\/code>is incremented and decremented. <code>oldHead <\/code>is removed from the stack and can, therefore, eventually be deleted with the call <code>tryToDelete <\/code>(line 5). The member function <code>tryToDelete <\/code>first checks if one or more <code>topAndPop <\/code>calls are active. If one <code>topAndPop <\/code>call is active (line 6), <code>oldHead <\/code>is deleted. If not, <code>oldHead <\/code>is added to the to-be-deleted list (line 7). I assume that only one <code>topAndPop <\/code>call is active. In this case, I create a local pointer <code>copyOfToBeDeletedNodes <\/code>to the to-be-deleted nodes and set the <code>toBeDeletedNodes <\/code>pointer to a <code>nullptr <\/code>(line 8). Before I delete the nodes, I check that no additional <code>topAndPop <\/code>call is active in the meantime. If the current execution <code>topAndPop <\/code>is still the only one, I use the local pointer <code>copyOfToBeDeletedNodes <\/code>to delete the list of all to-be-deleted nodes (line 9). If another <code>topAndPop <\/code>call interleaved, I use the local pointer <code>copyOfToBeDeletedNodes <\/code>to update <code>toBeDeletedNodes <\/code>pointer.<\/p>\n\n\n\n<p><br>Both helper member functions <code>addNodeToBeDeletedNodes <\/code>and <code>deleteAllNodes <\/code>iterate through the list. <code>deleteAllNodes <\/code>is only invoked if one <code>topAndPop <\/code>call is active. Consequentially, no synchronization is necessary. This observation does not hold for the member function <code>addNodeToBeDeletedNodes <\/code>(lines 9 and 7). It must be synchronized because more than one <code>topAndPop <\/code>call can be active. The while loop makes the <code>oldHead <\/code>the first node in the to-be-deleted nodes and uses a<code> compare_exchange_strong<\/code> to deal with the fact that topAndPop calls can interleave. Interleaving topAndPop calls cause that <code>oldHead-&gt;next !=<\/code> <code>toBeDeletedNodes <\/code>(line 10) and <code>oldHead-&gt;next <\/code>has to be updated to the <code>toBeDeletedNodes<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"591\" height=\"217\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/02\/lockFreeStackWithGarbageCollection.png\" alt=\"\" class=\"wp-image-10676\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/02\/lockFreeStackWithGarbageCollection.png 591w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/02\/lockFreeStackWithGarbageCollection-300x110.png 300w\" sizes=\"auto, (max-width: 591px) 100vw, 591px\" \/><\/figure>\n\n\n\n<p>So far, this lock-free stack implementation works as expected but has a few flaws. When many<br><code>topAndPop <\/code>calls interleave. it may happen that the counter <code>topAndPopCounter <\/code>never becomes one. It means that the nodes in the to-be-deleted lists of nodes are not deleted, and we have a memory leak. Additionally, the number of the to-be-deleted nodes may become a resource issue.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What\u00b4s Next?<\/h2>\n\n\n\n<p>Thanks to RCU and Hazard Pointers, these issues can be solved in C++26.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>My next lock-free stack includes a simple garbage collector. I discussed the concurrent execution of more than one topAndPush call is a Race Condition. I can safely delete a node if not more than one topAndPush call is executing concurrently. This observation is crucial for solving this memory leak issue: I store removed nodes on [&hellip;]<\/p>\n","protected":false},"author":21,"featured_media":10580,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[559],"tags":[563],"class_list":["post-10666","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c26-blog","tag-hazard-pointers"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10666","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/comments?post=10666"}],"version-history":[{"count":10,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10666\/revisions"}],"predecessor-version":[{"id":10678,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10666\/revisions\/10678"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/10580"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=10666"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=10666"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=10666"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}