‹ 返回视频系列: 持久内存编程入门

持久内存编程(第 5 节)C++ 示例

  • 概览
  • 资源
  • 文字稿

Andy Rudoff 是英特尔公司的非易失性内存软件架构师,也是存储网络行业协会 ( SNIA) 非易失性内存编程技术工作组的成员。在这段视频中,Andy 讲解了一个实施持久内存常驻队列的 C++ 示例。“libpmemobj”库用于对队列执行事务性更新。Andy 首先讲解了代码,然后运行程序示例(选自 NVM 库 GitHub repo),并展示了它的工作原理。

大家好,我是英特尔公司的 Andy Rudoff。开源 NVM 库简化了持久内存编程。在这段视频中,我们将展示一个使用 NVM 创建持久内存常驻队列数据结构的 C++ 示例。让我们首先创建一个用于实施队列示例的 C++ 程序。我将讲解一个选自下方 Git Hub 链接的示例,让我们直接来看有趣的部分。

我们首先创建一个包含头指针和尾指针的分类 pmem 队列。请注意持久指针模板在这里包含了类型名。这表明指针指向持久内存中的对象。普通 C++ 指针无法直接指向持久内存,您必须使用持久指针。这可以在同时使用持久数据结构和易失性数据结构时防止编程错误。

接下来,我们要定义每次向队列添加新项目时要分配的 struct pmem_entry。由于队列的元素以链接表的形式存储,我们在这里还是要使用持久指针模板为队列中的下一个条目提供一个链接。每个条目还包含一个值:uint64t。由于这个值常驻在持久内存中,我们使用 p 模板向库表明这一属性,请看屏幕。

当我们的示例程序打开 pmem 池时,它提供了一个布局名称,这就是该程序用来为 pmem 池中的内容命名的字符串。该布局名称要通过验证,从而确保其与创建该 pmem 池时使用的布局名称一致。我们的 open 调用也包含了这个根对象的类型。这让这里的 get_root 函数在定位根对象时获悉它的类型。

执行完这一行后,队列变量指向持久内存池中的根对象。接下来,我们的示例程序将根据在运行时被赋予的命令行参数决定是在队列上推送一个新值、取回一个现有值还是显示整个队列的内容。

现在,让我们检查一下向队列添加新条目的代码。我们需要把这部分代码写成事务代码,使其在发生故障时或者完整执行或者完全不执行。这要使用 C++ lambda 语法实现,请看屏幕。lambda 是一个无名函数,它的代码在大括号里。大括号里的所有内容都是事务的组成部分,包括由 make_persistent 实现的持久内存分配。如果该事务发生中断,任何持久内存分配(或冻结)以及对持久内存数据结构执行的任何其它变更都会由库自动回滚。

您可以看到分配、条目字段的初始化以及头指针和尾指针的更新在持久内存中都以单一事务的形式发生。从队列中提取一个元素也采取类似的事务形式。请注意看如果我们检测到任何异常,如何中止事务。中止操作将对该事务进行回滚,就像程序崩溃时一样。

当示例程序构建完成后,我们可以创建一个 pmem 池文件并运行该程序。首先,我们按照我在这个播放列表的另一段视频中讲的方法创建 pmem 池。注意这里提供的布局名称与示例程序预期的布局一致。初始队列是空的。现在您可以看到我向队列添加了多个项目,并将其从持久内存中保存的队列内容中取回。

NVML 示例目录中提供了完整的队列示例和更多其它示例。记得访问 pmem.io 网站获取更多详细的 C 语言和 C++ 示例。