【问题标题】:Multi-Threaded Deep Copies多线程深拷贝
【发布时间】:2010-09-15 15:45:32
【问题描述】:

在作为多线程 C++ 代码一部分的对象的构造函数中执行深拷贝的最佳方法是什么?

【问题讨论】:

    标签: c++ multithreading constructor


    【解决方案1】:

    取决于您的数据结构。

    我猜你面临的问题(虽然你没有这么说)是潜在的锁定反转。如果您正在深度复制,那么您可能会为需要复制的各种对象使用一个或多个锁。

    如果您可以定义一个 DAG(即偏序),其中节点是系统中的每个锁,并且您可能想要获取的每个锁组合都由边连接,那么您可以确保锁是从来没有在不同的线程中采取不同的顺序。因此,特别是您不会获得锁定反转。一个典型的规则是最后使用“最通用”的锁,因为这样可以最大限度地减少争用。

    但是,如果您要深度复制一大堆“WidgetBox”中的一个,每个“WidgetBox”都包含基本上无法区分的“Widget”,并且框的内容之间可能存在重叠,那么您自然会遇到定义锁定顺序的问题。此外,您必须首先锁定 WidgetBox(即使它是“最通用”的对象),因为没有该锁定,您无法确定还需要锁定什么。如果小部件具有可比性,您可能可以按顺序锁定每个小部件,复制并释放所有内容。讨厌。

    另一种方法是定义一个在所有 Widget 和 WidgetBox 之间共享的单一锁。这可能会引发很多争用,在这种情况下,乐观锁定可能会有所改善,前提是副本不会同时发生太多修改。

    另一种选择可能是放宽您对副本所做的保证 - 您可以首先锁定 WidgetBox,浅复制它(使用引用计数或其他方法),而不是要求从深层结构的可识别状态制作完整副本- 引用计数上的锁定通常是“最终内部锁定”,因此没有反转风险),释放 WidgetBox 锁定,然后依次复制每个 Widget。如果 Widget 具有内部结构,请使用相同的方法来复制它们。结果可能包含一个 Widget,直到它从另一个线程中的 WidgetBox 中删除后才实现,或者其他类似的不协调,所以如果这是不可接受的,那么你不能使用这种方法。但是,如果您在每个线程中一次只锁定一个对象,那么您将无法获得锁定反转。

    最后一个可能的“核”选项是使所有内容不可变,并始终在修改时复制。如果什么都不能被修改,那么你就不需要任何锁(尽管在线程之间传递引用时你仍然需要内存屏障)。

    如果这些都不起作用,那么除非我忘记了某些东西,否则你就超出了我的经验。我推测数据库实现是很多与锁相关的聪明才智的地方,这将是寻求想法的领域。

    【讨论】:

      【解决方案2】:

      fork()

      我只是在开玩笑。但是太有趣了,不能放弃:)

      我认为 onebyone 已经涵盖了您的大部分选择。除了,也许,退后一步,看看你是否能找到一种方法来避免一开始就进行深拷贝......

      【讨论】:

        【解决方案3】:

        我的第一个冲动(我不是专家):

        锁定代码用于写入的那个对象。进行深度复制时,锁定对象,执行深度复制,然后解锁。

        或者,我在这里遗漏了什么?

        【讨论】:

        • 不像听起来那么容易,因为这里涉及到一个深层副本。对象图中的不同数据片段可能存在许多锁。非常非常容易错过或陷入僵局。
        猜你喜欢
        • 2012-04-12
        • 2015-01-13
        • 2011-09-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-08
        • 2010-12-28
        • 2012-04-13
        相关资源
        最近更新 更多