[英]Using copy-on-write in multithreading environment in C++
在我的 Qt C++ 应用程序中,我有两个主线程:GUI 线程和渲染线程。 GUI 线程管理可以创建和编辑的DataObject
结构列表,而渲染线程绘制对象(渲染线程无法修改数据对象)。 我需要一种在两个线程之间共享数据对象的方法(渲染线程每帧可以渲染数千个对象,并且对象通常存储数百对浮点数)。 目前,我的设计策略包括存储数据对象的shared_ptr
并将共享指针列表从 GUI 线程传递到渲染线程。 当 GUI 线程正在修改数据 object 并且渲染线程也试图读取相同的数据 object 时,我正在使用互斥锁和锁来防止数据竞争。
另一方面,在查看 Qt 源代码时,我发现大量使用了写时复制技术,该技术本质上涉及数据对象的浅拷贝(当访问为只读时)和深拷贝用于写访问。 Qt 还提供了方便的类,如QSharedData类来实现您自己的隐式共享对象。
所以就我而言,我正在考虑使用写时复制,以便我可以使用这种技术实现我的DataObject
。 除了将共享指针传递给渲染线程,我可以直接传递DataObject
实例(当然在内部,数据仍然使用指针存储),如果 GUI 线程试图修改数据 object,它只会复制数据和两个线程将继续运行,就好像它们拥有数据 object 一样(渲染线程最终会丢弃其副本)。 现在,在我看来,写时复制在 C++ 世界(Qt 之外)中非常不受欢迎,而且我还没有找到很多其他代码库中使用它的例子。 在我的场景中使用写时复制有什么缺点? 有什么我应该注意的陷阱吗?
有一种非常简单的方法可以在某种程度上使锁变得不必要:
std::unique_ptr<T>
。 这确保只有有限数量的代码可以访问 object。 请注意,您显然在此阶段不共享指针,否则这不起作用。 总之,在写作时,你想要独占访问。std::shared_ptr<T const>
。 这允许共享并确保最后一个所有者在使用后删除动态资源。 这里的限制是它只允许只读访问。 总之,你放弃写作,因为你想要共享访问。笔记:
x
包含指针p
,您仍然可以使用该指针进行写入,即使x
是对 const 的引用。 指针本身将是常量,但指针对象不会继承它。 这在使用智能指针时也保持不变!unique_ptr
。 由于独占所有权,这也使得 object 上的互斥锁同步变得不必要。 典型应用是使用带有参数和结果的“任务”object。 一个线程(生产者)使用参数创建任务 object,然后另一个线程获得所有权(消费者)并计算结果。 然后它经常将 object 返回给初始生产者或将其传递给其他地方,充当生产者本身。在这种情况下使用写时复制语义可能很有用,但性能(提升)可能取决于每个渲染周期之间更改的数据量。 如果更改了很多数据,几乎所有的数据都会被复制。 首先将数据复制(或移动)到渲染线程可能会更有效,因为它避免了写时复制检查的开销。 使用写时复制行为的另一个缺点是隐式共享迭代器问题,当隐式共享 object 在迭代器仍处于活动状态时被分离时,就会出现这种问题。
使用写时复制,在您的情况下具有一些优势(与互斥锁和/或深复制到渲染线程相比):
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.