读取复制更新 (RCU)
Linux内核中广泛使用的一种锁原语是读复制更新(RCU)锁。它是一种同步机制,于 2002 年 10 月添加到 Linux 内核中。它通过使读取与更新同时发生而取得了改进。它支持多个读取器和单个更新器之间的并发。 RCU 的读端原语中没有开销。它是最安全的数据结构之一,旨在在同时访问期间安全运行,因为它有效地使用了缓存线和内存。
读复制更新 (CPU)锁有一个无锁读关键部分。 RCU 锁适用于写入器与无锁读取器兼容的工作负载。读临界区不允许抢占。
考虑以下代码:
struct Node
{
int key, val;
/* pointer to the "next" and "prev"(previous) node */
struct Node *next, *prev;
}
/* Searches for a given key node in a list li and,
returns the value corresponding to that key*/
int search(struct Node *li, int key)
{
int ret= -1;
preempt_disable();
/* Disabling the preempt */
while(li!=NULL)
{
/* The required key is found */
if(li->key == key)
{
/* Assigning "ret" the value of that particular key */
ret = li->val;
break;
}
/* moving on to the next list value */
li=li->next;
}
/* Enabling the interrupt which was disabled earlier */
preempt_enable();
/* Return the value of the key that is found */
return ret;
}
/* Deletes a given node */
void delete (struct Node *node)
{
/* Take a spin lock on the given node */
spin_lock(&lock);
node->next->prev = node->prev;
node->prev->next = node->next;
/* Unlock the lock on the node,
because the deletion has been done */
spin_unlock(&lock);
free(node);
}
上面代码中next(即node->prev->next = node->next)的删除更新是原子的,因为存储操作是原子的。如果同时执行删除,则搜索例程将根据 next 是否更新来查看新列表或旧列表。此外,删除操作可以与搜索操作同时执行,因为对搜索很重要的更新是链表节点的下一个字段的更新。
在读复制更新方案中,空闲操作被延迟,直到更新程序 100% 确定其他线程没有对将被删除的对象的引用。由于读关键部分不允许抢占,因此调用 RCU 计划表明特定内核没有执行读关键部分。
在 RCU 方案中,写入器调用rcu_free而不是free .rcu_free 确保所有读取器在调用 rcu_free 后至少从其临界区退出一次。此检查确保其他线程没有对将要删除的对象的活动引用。
当rcu_free调用wait_for_rcu 时,它会在每个核心上强制处于静止状态。wait_for_rcu 在所有核心上调度当前线程以强制执行挂起空闲的安全点。
的优点和缺点:
RCU 锁不能用于像树这样的数据结构,因为树搜索可能依赖于不能以原子方式完成的多个更新。
读复制更新锁的一个缺点是它需要禁用抢占,因为它们不能在用户模式下使用。