Table of Contents

RCU

RCU (Read-Copy-Update) is a synchronization scheme where readers access shared data with zero locking overhead, while writers copy the data, modify the copy, and atomically swap a pointer. Readers that held the old pointer before the swap continue using stale but valid data. The writer waits for a grace period—until all readers that could have seen the old pointer have finished—before freeing it.

RCU is a clear win when reads vastly outnumber writes; it trades memory and write latency for essentially free reads.

Example

This example demonstrates RCU semantics with copy-on-write updates.

// compile: gcc -std=c11 -pthread -O2 -o rcu rcu.c
// run: ./rcu
// description: RCU pattern with readers seeing old or new version
 
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdatomic.h>
#include <unistd.h>
 
struct data {
    int value;
};
 
atomic_intptr_t global_ptr = 0;
 
void* reader(void* arg) {
    for (int i = 0; i < 5; i++) {
        struct data* d = (struct data*)atomic_load(&global_ptr);
        if (d) {
            printf("Reader: value = %d\n", d->value);
        }
        usleep(100000);
    }
    return NULL;
}
 
void* writer(void* arg) {
    sleep(1);
    struct data* old = (struct data*)atomic_load(&global_ptr);
    struct data* new = malloc(sizeof(struct data));
    new->value = 42;
    atomic_store(&global_ptr, (intptr_t)new);
    printf("Writer: updated value\n");
    // In real RCU, wait for grace period before freeing old
    sleep(1);
    free(old);
    return NULL;
}
 
int main() {
    global_ptr = (intptr_t)malloc(sizeof(struct data));
    ((struct data*)global_ptr)->value = 0;
 
    pthread_t readers[2], w;
    for (int i = 0; i < 2; i++) {
        pthread_create(&readers[i], NULL, reader, NULL);
    }
    pthread_create(&w, NULL, writer, NULL);
 
    for (int i = 0; i < 2; i++) pthread_join(readers[i], NULL);
    pthread_join(w, NULL);
    free((void*)global_ptr);
    return 0;
}