Incomputer science,read-copy-update (RCU) is asynchronization mechanism that avoids the use oflock primitives while multiplethreads concurrently read and update elements that are linked throughpointers and that belong to shareddata structures (e.g.,linked lists,trees,hash tables).[1]
Whenever a thread is inserting or deleting elements of data structures inshared memory, all readers are guaranteed to see and traverse either the older or the new structure, therefore avoiding inconsistencies (e.g., dereferencingnull pointers).[1]
It is used when performance of reads is crucial and is an example ofspace–time tradeoff, enabling fast operations at the cost of more space. This makes all readers proceed as if there were nosynchronization involved, hence they will be fast, but also making updates more difficult.
The name comes from the way that RCU is used to update a linked structure in place. A thread wishing to do this uses the following steps:
So the structure isread concurrently with a threadcopying in order to do anupdate, hence the name "read-copy update". The abbreviation "RCU" was one of many contributions by the Linux community. Other names for similar techniques includepassive serialization andMP defer byVM/XA programmers andgenerations byK42 andTornado programmers.

A key property of RCU is that readers can access a data structure even when it is in the process of being updated: RCU updaters cannot block readers or force them to retry their accesses. This overview starts by showing how data can be safely inserted into and deleted from linked structures despite concurrent readers. The first diagram on the right depicts a four-state insertion procedure, with time advancing from left to right.
The first state shows a global pointer namedgptr that is initiallyNULL, colored red to indicate that it might be accessed by a reader at any time, thus requiring updaters to take care. Allocating memory for a new structure transitions to the second state. This structure has indeterminate state (indicated by the question marks) but is inaccessible to readers (indicated by the green color). Because the structure is inaccessible to readers, the updater may carry out any desired operation without fear of disrupting concurrent readers. Initializing this new structure transitions to the third state, which shows the initialized values of the structure's fields. Assigning a reference to this new structure togptr transitions to the fourth and final state. In this state, the structure is accessible to readers, and is therefore colored red. Thercu_assign_pointer primitive is used to carry out this assignment and ensures that the assignment is atomic in the sense that concurrent readers will either see aNULL pointer or a valid pointer to the new structure, but not some mash-up of the two values. Additional properties ofrcu_assign_pointer are described later in this article.

This procedure demonstrates how new data may be inserted into a linked data structure even though readers are concurrently traversing the data structure before, during, and after the insertion. The second diagram on the right depicts a four-state deletion procedure, again with time advancing from left to right.
The first state shows a linked list containing elementsA,B, andC. All three elements are colored red to indicate that an RCU reader might reference any of them at any time. Usinglist_del_rcu to remove elementB from this list transitions to the second state. Note that the link from element B to C is left intact in order to allow readers currently referencing elementB to traverse the remainder of the list. Readers accessing the link from elementA will either obtain a reference to elementB or elementC, but either way, each reader will see a valid and correctly formatted linked list. ElementB is now colored yellow to indicate that while pre-existing readers might still have a reference to elementB, new readers have no way to obtain a reference. A wait-for-readers operation transitions to the third state. Note that this wait-for-readers operation need only wait for pre-existing readers, but not new readers. ElementB is now colored green to indicate that readers can no longer be referencing it. Therefore, it is now safe for the updater to free elementB, thus transitioning to the fourth and final state.
It is important to reiterate that in the second state different readers can see two different versions of the list, either with or without elementB. In other words, RCU provides coordination in space (different versions of the list) as well as in time (different states in the deletion procedures). This is in stark contrast with more traditional synchronization primitives such aslocking ortransactions that coordinate in time, but not in space.
This procedure demonstrates how old data may be removed from a linked data structure even though readers are concurrently traversing the data structure before, during, and after the deletion. Given insertion and deletion, a wide variety of data structures can be implemented using RCU.
RCU's readers execute withinread-side critical sections, which are normally delimited byrcu_read_lock andrcu_read_unlock. Any statement that is not within an RCU read-side critical section is said to be in aquiescent state, and such statements are not permitted to hold references to RCU-protected data structures, nor is the wait-for-readers operation required to wait for threads in quiescent states. Any time period during which each thread resides at least once in a quiescent state is called agrace period. By definition, any RCU read-side critical section in existence at the beginning of a given grace period must complete before the end of that grace period, which constitutes the fundamental guarantee provided by RCU. In addition, the wait-for-readers operation must wait for at least one grace period to elapse. It turns out that this guarantee can be provided with extremely small read-side overheads, in fact, in the limiting case that is actually realized by server-class Linux-kernel builds, the read-side overhead is exactly zero.[2]
RCU's fundamental guarantee may be used by splitting updates intoremoval andreclamation phases. The removal phase removes references to data items within a data structure (possibly by replacing them with references to new versions of these data items) and can run concurrently with RCU read-side critical sections. The reason that it is safe to run the removal phase concurrently with RCU readers is the semantics of modern CPUs guarantee that readers will see either the old or the new version of the data structure rather than a partially updated reference. Once a grace period has elapsed, there can no longer be any readers referencing the old version, so it is then safe for the reclamation phase to free (reclaim) the data items that made up that old version.[3]
Splitting an update into removal and reclamation phases allows the updater to perform the removal phase immediately, and to defer the reclamation phase until all readers active during the removal phase have completed, in other words, until a grace period has elapsed.[note 1]
So, the typical RCU update sequence goes something like the following:[4]
In the above procedure (which matches the earlier diagram), the updater is performing both the removal and the reclamation step, but it is often helpful for an entirely different thread to do the reclamation. Reference counting can be used to let the reader perform removal so, even if the same thread performs both the update step (step (2) above) and the reclamation step (step (4) above), it is often helpful to think of them separately.
RCU is perhaps the most commonnon-blocking algorithm for a shared data structure. RCU is completely wait-free for any number of readers. Single-writer implementations RCU are also lock-free for the writer.[5] Some multi-writer implementations of RCU are lock-free.[6] Other multi-writer implementations of RCU serialize writers with a lock.[7]
By early 2008, there were almost 2,000 uses of the RCU API within the Linux kernel[8] including the networking protocol stacks[9] and the memory-management system.[10] As of March 2014[update], there were more than 9,000 uses.[11] Since 2006, researchers have applied RCU and similar techniques to a number of problems, including management of metadata used in dynamic analysis,[12] managing the lifetime of clustered objects,[13] managing object lifetime in theK42 research operating system,[14][15] and optimizingsoftware transactional memory implementations.[16][17]Dragonfly BSD uses a technique similar to RCU that most closely resembles Linux's Sleepable RCU (SRCU) implementation.
The ability to wait until all readers are done allows RCU readers to use much lighter-weight synchronization—in some cases, absolutely no synchronization at all. In contrast, in more conventional lock-based schemes, readers must use heavy-weight synchronization in order to prevent an updater from deleting the data structure out from under them. The reason is that lock-based updaters typically update data in place and must therefore exclude readers. In contrast, RCU-based updaters typically take advantage of the fact that writes to single aligned pointers are atomic on modern CPUs, allowing atomic insertion, removal, and replacement of data in a linked structure without disrupting readers. Concurrent RCU readers can then continue accessing the old versions and can dispense with the atomic read-modify-write instructions, memory barriers, and cache misses that are so expensive on modernSMP computer systems, even in absence of lock contention.[18][19] The lightweight nature of RCU's read-side primitives provides additional advantages beyond excellent performance, scalability, and real-time response. For example, they provide immunity to mostdeadlock andlivelock conditions.[note 3]
Of course, RCU also has disadvantages. For example, RCU is a specialized technique that works best in situations with mostly reads and few updates but is often less applicable to update-only workloads. For another example, although the fact that RCU readers and updaters may execute concurrently is what enables the lightweight nature of RCU's read-side primitives, some algorithms may not be amenable to read/update concurrency.
Despite well over a decade of experience with RCU, the exact extent of its applicability is still a research topic.
The technique is covered byU.S.software patentU.S. patent 5,442,758, issued August 15, 1995, and assigned toSequent Computer Systems, as well as byU.S. patent 5,608,893 (expired 2009-03-30),U.S. patent 5,727,209 (expired 2010-04-05),U.S. patent 6,219,690 (expired 2009-05-18), andU.S. patent 6,886,162 (expired 2009-05-25). The now-expired US PatentU.S. patent 4,809,168 covers a closely related technique. RCU is also the topic of one claim in theSCO v. IBMlawsuit.
RCU is available in a number of operating systems and was added to theLinux kernel in October 2002. User-level implementations such asliburcu are also available.[20]
The implementation of RCU in version 2.6 of the Linux kernel is among the better-known RCU implementations and will be used as an inspiration for the RCU API in the remainder of this article. The core API (Application Programming Interface) is quite small:[21]
synchronize_rcu willnot necessarily wait for any subsequent RCU read-side critical sections to complete. For example, consider the following sequence of events:CPU 0 CPU 1 CPU 2 ----------------- ------------------------- --------------- 1. rcu_read_lock() 2. enters synchronize_rcu() 3. rcu_read_lock() 4. rcu_read_unlock() 5. exits synchronize_rcu() 6. rcu_read_unlock()
synchronize_rcu is the API that must figure out when readers are done, its implementation is key to RCU. For RCU to be useful in all but the most read-intensive situations,synchronize_rcu's overhead must also be quite small.call_rcu in the Linux kernel.rcu_dereference to fetch an RCU-protected pointer, which returns a value that may then be safely dereferenced. It also executes any directives required by the compiler or the CPU, for example, a volatile cast for gcc, a memory_order_consume load for C/C++11 or the memory-barrier instruction required by the old DEC Alpha CPU. The value returned byrcu_dereference is valid only within the enclosing RCU read-side critical section. As withrcu_assign_pointer, an important function ofrcu_dereference is to document which pointers are protected by RCU.
The diagram on the right shows how each API communicates among the reader, updater, and reclaimer.
The RCU infrastructure observes the time sequence ofrcu_read_lock,rcu_read_unlock,synchronize_rcu, andcall_rcu invocations in order to determine when (1)synchronize_rcu invocations may return to their callers and (2)call_rcu callbacks may be invoked. Efficient implementations of the RCU infrastructure make heavy use of batching in order to amortize their overhead over many uses of the corresponding APIs.
RCU has extremely simple "toy" implementations that can aid understanding of RCU. This section presents one such "toy" implementation that works in anon-preemptive environment.[22]
voidrcu_read_lock(void){}voidrcu_read_unlock(void){}voidcall_rcu(void(*callback)(void*),void*arg){// add callback/arg pair to a list}voidsynchronize_rcu(void){intcpu,ncpus=0;foreach_cpu(cpu)schedule_current_task_to(cpu);foreachentryinthecall_rculistentry->callback(entry->arg);}
In the code sample,rcu_assign_pointer andrcu_dereference can be ignored without missing much. However, they are needed in order to suppress harmful compiler optimization and to prevent CPUs from reordering accesses.
#define rcu_assign_pointer(p, v) ({ \ smp_wmb();/* Order previous writes. */ \ ACCESS_ONCE(p) = (v); \})#define rcu_dereference(p) ({ \ typeof(p) _value = ACCESS_ONCE(p); \ smp_read_barrier_depends();/* nop on most architectures */ \ (_value); \})
Note thatrcu_read_lock andrcu_read_unlock do nothing. This is the great strength of classic RCU in a non-preemptive kernel: read-side overhead is precisely zero, assmp_read_barrier_depends() is an empty macro on all butDEC Alpha CPUs;[23][failed verification] such memory barriers are not needed on modern CPUs. TheACCESS_ONCE() macro is a volatile cast that generates no additional code in most cases. And there is no way thatrcu_read_lock can participate in adeadlock cycle, cause a realtime process to miss its scheduling deadline, precipitatepriority inversion, or result in highlock contention. However, in this toy RCU implementation, blocking within an RCU read-side critical section is illegal, just as is blocking while holding a pure spinlock.
The implementation ofsynchronize_rcu moves the caller of synchronize_cpu to each CPU, thus blocking until all CPUs have been able to perform the context switch. Recall that this is a non-preemptive environment and that blocking within an RCU read-side critical section is illegal, which imply that there can be no preemption points within an RCU read-side critical section. Therefore, if a given CPU executes a context switch (to schedule another process), we know that this CPU must have completed all preceding RCU read-side critical sections. Once all CPUs have executed a context switch, then all preceding RCU read-side critical sections will have completed.
Although RCU can be used in many different ways, a very common use of RCU is analogous to reader–writer locking. The following side-by-side code display shows how closely related reader–writer locking and RCU can be.[24]
/* reader-writer locking *//* RCU */1structel{1structel{2structlist_headlp;2structlist_headlp;3longkey;3longkey;4spinlock_tmutex;4spinlock_tmutex;5intdata;5intdata;6/* Other data fields */6/* Other data fields */7};7};8DEFINE_RWLOCK(listmutex);8DEFINE_SPINLOCK(listmutex);9LIST_HEAD(head);9LIST_HEAD(head);1intsearch(longkey,int*result)1intsearch(longkey,int*result)2{2{3structel*p;3structel*p;445read_lock(&listmutex);5rcu_read_lock();6list_for_each_entry(p,&head,lp){6list_for_each_entry_rcu(p,&head,lp){7if(p->key==key){7if(p->key==key){8*result=p->data;8*result=p->data;9read_unlock(&listmutex);9rcu_read_unlock();10return1;10return1;11}11}12}12}13read_unlock(&listmutex);13rcu_read_unlock();14return0;14return0;15}15}1intdelete(longkey)1intdelete(longkey)2{2{3structel*p;3structel*p;445write_lock(&listmutex);5spin_lock(&listmutex);6list_for_each_entry(p,&head,lp){6list_for_each_entry(p,&head,lp){7if(p->key==key){7if(p->key==key){8list_del(&p->lp);8list_del_rcu(&p->lp);9write_unlock(&listmutex);9spin_unlock(&listmutex);10synchronize_rcu();10kfree(p);11kfree(p);11return1;12return1;12}13}13}14}14write_unlock(&listmutex);15spin_unlock(&listmutex);15return0;16return0;16}17}
The differences between the two approaches are quite small. Read-side locking moves torcu_read_lock andrcu_read_unlock, update-side locking moves from a reader-writer lock to a simple spinlock, and asynchronize_rcu precedes thekfree.
However, there is one potential catch: the read-side and update-side critical sections can now run concurrently. In many cases, this will not be a problem, but it is necessary to check carefully regardless. For example, if multiple independent list updates must be seen as a single atomic update, converting to RCU will require special care.
Also, the presence ofsynchronize_rcu means that the RCU version ofdelete can now block. If this is a problem,call_rcu could be used likecall_rcu (kfree, p) in place ofsynchronize_rcu. This is especially useful in combination with reference counting.
This sectionis inlist format but may read better asprose. You can help byconverting this section, if appropriate.Editing help is available.(May 2014) |
Techniques and mechanisms resembling RCU have been independently invented multiple times:[25]
{{cite conference}}:External link in|journal= (help){{cite book}}: CS1 maint: location missing publisher (link)Bauer, R.T., (June 2009), "Operational Verification of a Relativistic Program" PSU Tech Report TR-09-04 (http://www.pdx.edu/sites/www.pdx.edu.computer-science/files/tr0904.pdfArchived 2015-06-18 at theWayback Machine)