1

我将 RCU 保护的指针存储MyStruct *在 RCU 保护的哈希表MyHash中。通过哈希表读取/更新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's 还是仅仅拥有外部rcu_read_lock/rcu_read_unlock就足够了?

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

4

1 回答 1

2

rcu_read_lock()不,不需要嵌套。

与其他“嵌套”临界区类似,嵌套的唯一作用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'*/
于 2019-11-26T14:49:46.793 回答