{"id":10769,"date":"2025-06-02T09:54:01","date_gmt":"2025-06-02T09:54:01","guid":{"rendered":"https:\/\/www.modernescpp.com\/?p=10769"},"modified":"2025-07-03T14:42:05","modified_gmt":"2025-07-03T14:42:05","slug":"read-copy-update-rcu","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/read-copy-update-rcu\/","title":{"rendered":"Read-copy-update (RCU)"},"content":{"rendered":"\n<p>Read-copy-update is strong in multithreading environments where a data structure is read almost exclusively but rarely written.<\/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>First of all, what is RCU? The excellent Wikipedia page on <a href=\"https:\/\/en.wikipedia.org\/wiki\/Read-copy-update\">Read-copy-update <\/a>provides a good introduction:<\/p>\n\n\n\n<p><em>In <a href=\"https:\/\/en.wikipedia.org\/wiki\/Computer_science\">computer science<\/a>, <strong>read-copy-update<\/strong> (<strong>RCU<\/strong>) is a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Synchronization_(computer_science)\">synchronization<\/a> mechanism that avoids the use of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Lock_(computer_science)\">lock<\/a> primitives while multiple <a href=\"https:\/\/en.wikipedia.org\/wiki\/Thread_(computing)\">threads<\/a> concurrently read and update elements that are linked through <a href=\"https:\/\/en.wikipedia.org\/wiki\/Pointer_(computer_programming)\">pointers<\/a> and that belong to shared <a href=\"https:\/\/en.wikipedia.org\/wiki\/Data_structure\">data structures<\/a> (e.g., <a href=\"https:\/\/en.wikipedia.org\/wiki\/Linked_lists\">linked lists<\/a>, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Tree_(data_structure)\">trees<\/a>, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Hash_table\">hash tables<\/a>).<sup><a href=\"https:\/\/en.wikipedia.org\/wiki\/Read-copy-update#cite_note-:0-1\">[1]<\/a><\/sup><\/em><\/p>\n\n\n\n<p><em>Whenever a thread is inserting or deleting elements of data structures in <a href=\"https:\/\/en.wikipedia.org\/wiki\/Shared_memory\">shared memory<\/a>, all readers are guaranteed to see and traverse either the older or the new structure, therefore avoiding inconsistencies (e.g., dereferencing <a href=\"https:\/\/en.wikipedia.org\/wiki\/Null_pointer\">null pointers<\/a>).<sup><a href=\"https:\/\/en.wikipedia.org\/wiki\/Read-copy-update#cite_note-:0-1\">[1]<\/a><\/sup><\/em><\/p>\n\n\n\n<p><em>It is used when performance of reads is crucial and is an example of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Space%E2%80%93time_tradeoff\">space\u2013time tradeoff<\/a>, enabling fast operations at the cost of more space. This makes all readers proceed as if there were no <a href=\"https:\/\/en.wikipedia.org\/wiki\/Synchronization_(computer_science)\">synchronization<\/a> involved, hence they will be fast, but also making updates more difficult.<\/em><\/p>\n\n\n\n<p>The name RCU was coined by the writer&#8217;s workflow. It first reads the current data, copies it to the new data, and then updates the current data.<\/p>\n\n\n\n<p><span style=\"text-decoration: underline;\">Proposal <a href=\"https:\/\/www.open-std.org\/jtc1\/sc22\/wg21\/docs\/papers\/2023\/p2545r4.pdf\">P2545R4 <\/a><\/span>provides three use cases for RCU, comparing them with <a href=\"https:\/\/www.modernescpp.com\/index.php\/reader-writer-locks\/\">reader-writer locks.<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Three Use Cases<\/h2>\n\n\n\n<p>The three use cases compare <a href=\"https:\/\/www.modernescpp.com\/index.php\/reader-writer-locks\/\">reader-writer locks.<\/a> with intrusive, non-intrusive, and synchronous RCU.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Intrusive RCU<\/h3>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"984\" height=\"562\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/Introsive.png\" alt=\"\" class=\"wp-image-10771\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/Introsive.png 984w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/Introsive-300x171.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/Introsive-768x439.png 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/Introsive-705x403.png 705w\" sizes=\"auto, (max-width: 984px) 100vw, 984px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Non-Intrusive RCU<\/h3>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1002\" height=\"565\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/non-intrusive.png\" alt=\"\" class=\"wp-image-10772\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/non-intrusive.png 1002w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/non-intrusive-300x169.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/non-intrusive-768x433.png 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/non-intrusive-705x398.png 705w\" sizes=\"auto, (max-width: 1002px) 100vw, 1002px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Synchronous RCU<\/h3>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"929\" height=\"570\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/synchronus.png\" alt=\"\" class=\"wp-image-10773\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/synchronus.png 929w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/synchronus-300x184.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/synchronus-768x471.png 768w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/synchronus-705x433.png 705w\" sizes=\"auto, (max-width: 929px) 100vw, 929px\" \/><\/figure>\n\n\n\n<p><br>The main difference between intrusive and non-intrusive RCU is that in the intrusive case, <code>Data <\/code>is derived directly from the class<code> struct Data : std::rcu_obj_base&lt;Data&gt;.<\/code> This technique, in which a template has itself as a parameter, is known as the<a href=\"https:\/\/www.modernescpp.com\/index.php\/c-is-still-lazy\/\"> Curiously Recurring Template Pattern <\/a>(CRTP). On the reader side, <code>std::scoped_lock l(std::rcu_default_domain()) <\/code>is used. On the writer side, either <code>retire() <\/code>or <code>std::rcu_synchronize() <\/code>is used.<\/p>\n\n\n\n<p>This raises the question: when should similar techniques such as atomic shared pointers, read-write locks, hazard pointers, and RCU be used? The <span style=\"text-decoration: underline;\">Proposal <a href=\"https:\/\/www.open-std.org\/jtc1\/sc22\/wg21\/docs\/papers\/2023\/p2545r4.pdf\">P2545R4 <\/a><\/span>provides a simple rule: <em>As a very rough rule of thumb, Hazard Pointers can be considered to be a scalable replacement for reference counters and RCU can be considered to be a scalable replacement for reader-writer locking. A high-level comparison of reference counting, Hazard Pointers, and RCU is displayed in Table 1. <br><\/em><\/p>\n\n\n\n<p>Here is Table 1:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"740\" height=\"180\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/Vergleich.png\" alt=\"\" class=\"wp-image-10777\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/Vergleich.png 740w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/Vergleich-300x73.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2025\/05\/Vergleich-705x171.png 705w\" sizes=\"auto, (max-width: 740px) 100vw, 740px\" \/><\/figure>\n\n\n\n<p>To conclude this article, here is the interface of RCU.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Interface<\/h2>\n\n\n\n<p>The interface consists of two classes, <code>rcu_obj_base <\/code>and <code>rcu_domain<\/code> and four functions, <code>rcu_default_domain<\/code>, <code>rcu_synchronize<\/code>, <code>rcu_barrier<\/code>, and <code>rcu_retire<\/code>.<\/p>\n\n\n\n<p><a href=\"https:\/\/en.cppreference.com\/w\/cpp\/header\/rcu.html\">cppreference <\/a>provides a concise description:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Classes<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>rcu_obj_base<\/code>: allows an object to be protected by RCU<\/li>\n\n\n\n<li><code>rcu_domain<\/code>: provides regions of RCU protection<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Functions<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>rcu_default_domain<\/code>: returns a reference to a static-duration object of type <code>std::rcu_domain<\/code><\/li>\n\n\n\n<li><code>rcu_synchronize<\/code>: blocks until a protection region unlocks on a RCU domain<\/li>\n\n\n\n<li><code>rcu_barrier<\/code>: may evaluate scheduled operations on a RCU domain and blocks until all preceding evaluations are complete<\/li>\n\n\n\n<li><code>rcu_retire<\/code>: schedules the evaluation of a specified function on a RCU domain, potentially allocating memory, and invoking scheduled evaluations<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">What\u2019s next?<\/h2>\n\n\n\n<p>The Data-parallel types (SIMD) library provides data-parallel types and operations on them. I will take a closer look at this library in my next article.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Read-copy-update is strong in multithreading environments where a data structure is read almost exclusively but rarely written. First of all, what is RCU? The excellent Wikipedia page on Read-copy-update provides a good introduction: In computer science, read-copy-update (RCU) is a synchronization mechanism that avoids the use of lock primitives while multiple threads concurrently read and [&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":[564],"class_list":["post-10769","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c26-blog","tag-rcu"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10769","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=10769"}],"version-history":[{"count":8,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10769\/revisions"}],"predecessor-version":[{"id":10782,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10769\/revisions\/10782"}],"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=10769"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=10769"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=10769"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}