问题1:
在介绍RCU锁的文章中,他写了一个publish-subscribe机制。但是我对rcu_assign_pointer()有一个疑问,在这篇文章中,他说:
1 p->a = 1;
2 p->b = 2;
3 p->c = 3;
4 rcu_assign_pointer(gp, p);
但是编译器和CPU怎么知道p已经被分配了呢?例如,如果我只是初始化p->a和p->b,那么编译器和CPU如何区分这两种情况?rcu_assign_pointer()会发布新的结构体,强制两者都发布编译器和CPU执行赋值给gp后对p.
引用的字段的赋值
situation 1:
1 p->a = 1;
2 p->b = 2;
3 p->c = 3;
4 rcu_assign_pointer(gp, p);
situation 2:
1 p->a = 1;
2 p->b = 2;
3 rcu_assign_pointer(gp, p);
问题2:
对于读侧临界区,如果有连续的读端在读数据,写端是必须等待还是不能进行同步操作?如果是,读者会一直读旧版本吗?
问题1的答案:rcu_assign_pointer()指示编译器不要优化机器指令,这样在rcu_assign_pointer()语句之前对'p'字段的任何修改,在实现/代码中,在'p'赋值给'gp'之前,在cpu管道中执行。这确保当'gp'被分配时,'p'的所有字段,因此现在'gp',开发人员选择分配确实被分配。
为了进一步说明,以以下代码为例,其目的是将'y'返回给调用者:
void
my_func(struct foo **y)
{
struct foo *x = malloc(sizeof (struct foo));
x->val1 = 1;
*y = x;
x->val2 = 2;
return;
}
开发人员并不真正关心上面赋值语句的顺序,因为他/她的意图只是简单地返回充满两个值的*y。因此,对于像上面这样的代码,编译器可以选择在cpu管道中并行执行3个赋值语句,这不会破坏正确性。
现在,如果你在做rcu类型的工作时使用类似的赋值语句,编译器可能会选择做同样的优化,因此读者可能最终得到一个"部分初始化"的"gp"。rcu_assign_pointer()确保了赋值的顺序被维护,这样开发人员的意图,即在p的所有字段初始化之后,将'p'赋值给'gp'。
希望这能说明,如果你,开发人员,选择只赋值p->a和p->b,而不赋值p->c,在将'p'赋值给'gp'之前,gp将得到-一个部分初始化的结构。
问题2的答案: