我将一个受RCU保护的指针存储在一个受RCU保护的哈希表MyHash
MyStruct *
中。通过哈希表读取/更新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()
不是必需的。
与其他"嵌套"关键部分类似,嵌套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'*/