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'*/
我将 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'*/