# 23.4 RCU实现(2) - Memory barrier

在前一部分介绍的方法中，存在一个问题。在前一部分中，如果要更新E2的内容，需要先创建一个E2‘ 并设置好它的内容，然后将E2’ 的next指针指向E3，最后才会将E1的next指针指向E2’。

![](/files/-MU2jBOCYmgpZHDvoijI)

你们或许还记得在XV6中曾经介绍过（注，详见10.8），许多计算机中都不存在“之后”或者“然后”这回事，通常来说所有的编译器和许多微处理器都会重排内存操作。如果我们用C代码表示刚才的过程：

![](/files/-MU2X9HEIf62M644Sxf6)

如果你测试这里的代码，它可能可以较好的运行，但是在实际中就会时不时的出错。这里的原因是编译器或者计算机可能会重排这里的写操作，也有可能编译器或者计算机会重排数据读取者的读操作顺序。如果我们在初始化E2’的内容之前，就将E1的next指针设置成E2‘，那么某些数据读取者可能就会读到垃圾数据并出错。

所以实现RCU的第二个部分就是数据读取者和数据写入者都需要使用memory barriers，这里背后的原因是因为我们这里没有使用锁。对于数据写入者来说，memory barrier应该放置在committing write之前，

![](/files/-MU2_N2kUev9MDR5N5oU)

这样可以告知编译器和硬件，先完成所有在barrier之前的写操作，再完成barrier之后的写操作。所以在E1设置next指针指向E2‘的时候，E2’必然已经完全初始化完了。

对于数据读取者，需要先将E1的next指针加载到某个临时寄存器中，我们假设r1保存了E1的next指针，之后数据读取者也需要一个memory barrier，然后数据读取者才能查看r1中保存的指针。

![](/files/-MU2a32t202_GTxBY9Jy)

这里的barrier表明的意思是，在完成E1的next指针读取之前，不要执行其他的数据读取，这样数据读取者从E1的next指针要么可以读到旧的E2，要么可以读到新的E2‘。通过barrier的保障，我们可以确保成功在r1中加载了E1的next指针之后，再读取r1中指针对应的内容。

因为数据写入者中包含的barrier确保了在committing write时，E2’已经初始化完成。如果数据读取者读到的是E2‘，数据读取者中包含的barrier确保了可以看到初始化之后E2’的内容。

> 学生提问：什么情况下才可能在将E1的next指针加载到r1之前，就先读取r1中指针指向的内容？
>
> Robert教授：我觉得你难住我了。一种可能是，不论r1指向的是什么，它或许已经在CPU核上有了缓存，或许一分钟之前这段内存被用作其他用途了，我们在CPU的缓存上有了E1->next对应地址的一个旧版本。我不确定这是不是会真的发生，这里都是我编的，如果r1->x可以使用旧的缓存的数据，那么我们将会有大麻烦。
>
> 说实话我不知道这个问题的答案，呵呵。我课下会想一个具体的例子。

以上是实现RCU的第二个部分。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mit-public-courses-cn-translatio.gitbook.io/mit6-s081/lec23-rcu-robert/23.4-rcu-shi-xian-2-memory-barrier.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
