rcu_read_locks 的嵌套

Nesting of rcu_read_locks

我将 RCU 保护的指针 MyStruct * 存储在 RCU 保护的哈希表 MyHash 中。当通过哈希表 reading/updating MyStruct 时,我如下所示。

rcu_read_lock() /* For hashtable 'MyHash' */
hash_for_each_possible_rcu(MyHash, obj, member, key)
{
    rcu_read_lock(); /* For RCU protected data(MyStruct*) stored in hashtable */
    Mystruct* s = rcu_dereference_pointer(obj->s);
    if(s) 
    {
        s->read++;
    }
    rcu_read_unlock(); /* For RCU protected data(MyStruct*) stored in hashtable */
}
rcu_read_unlock() /* For hashtable 'MyHash'*/

注意 MyStruct 本身是另一个 RCU 保护列表的一部分(即它是另一个列表的 RCU 保护节点),它存储在 MyHash 中以便更快地查找。

据我了解,需要 rcu_read_lock 来确保在所有读取端临界区完成之前,任何编写器更新都不会释放内存。那么,真的有必要嵌套 rcu_read_lock 还是只需要外部 rcu_read_lock/rcu_read_unlock 就足够了?

IOW,由于 RCU 锁不绑定到任何单个对象,当一起访问多个 RCU 保护对象时,我们真的需要嵌套的 rcu 锁吗?

否,嵌套 rcu_read_lock() 不需要

与其他"nested" 临界区类似,嵌套rcu_read_lock 的唯一作用是增加锁级别。也就是说,进一步 rcu_read_unlock 不会立即结束临界区,而只是恢复锁定级别。

然而,支持嵌套锁定被视为 RCU 锁定机制的优势。支持嵌套操作后,可以独立开发组件。

例如,您可能有 object_increment 可以在没有 RCU 锁的情况下安全调用的函数:

void object_increment(Object obj)
{
    rcu_read_lock();
    Mystruct* s = obj->s;
    if(s) 
    {
        s->read++;
    }
    rcu_read_unlock();
}

然后在RCU锁下调用这个函数:

rcu_read_lock(); /* For hashtable 'MyHash' */
hash_for_each_possible_rcu(MyHash, obj, member, key)
{
    // It is perfectly valid to use the function even with RCU lock already taken
    object_increment(obj);
}
rcu_read_unlock(); /* For hashtable 'MyHash'*/

简单的设计几乎总是比对 rcu_read_lock.

的嵌套调用的小性能影响更重要

如果不允许嵌套调用,则需要实现另一个组件的功能以使用 RCU 锁进行访问:

void object_increment_locked(Object obj)
{
    Mystruct* s = obj->s;
    if(s) 
    {
        s->read++;
    }
}

并仔细选择在具体情况下使用哪个功能(锁定或非锁定):

rcu_read_lock(); /* For hashtable 'MyHash' */
hash_for_each_possible_rcu(MyHash, obj, member, key)
{
    // Already have a lock taken, so use _locked version of the function.
    object_increment_locked(obj);
}
rcu_read_unlock(); /* For hashtable 'MyHash'*/