【问题标题】:Boost serialization: How does pointer tracking work?Boost 序列化:指针跟踪如何工作?
【发布时间】:2011-08-22 12:39:59
【问题描述】:

指针跟踪在 boost 序列化中是如何工作的?我用它来序列化系统组件之间的消息,我的印象是我得到了很多不正确的共享对象。是否有可能如果我使用指向要序列化的对象的共享指针并且新对象恰好与已被删除的先前对象具有相同的地址,这将被错误地捕获为共享引用?

【问题讨论】:

  • 这是单线程的,而不是序列化过程中大量线程之间的可怕竞争条件,对吧?
  • 是的,应该都相当安全。它是由单个消费者线程添加的所有共享指针。
  • 但是序列化操作根本不是原子操作 - 遍历所有需要序列化的对象可能需要很长时间,并且在此期间一个或多个可能已经改变,除非你是确保没有人可能改变。它永远不会与 shared_ptr 一起崩溃,但它很可能会产生您描述的那种不一致的状态。
  • 我不认为这是正在发生的事情。我认为这更多的是你得到一个指向某个地址的共享指针,它被序列化,删除,一个新的共享指针被创建,巧合的相同地址,它被序列化,并被选为错误的共享地址......我解决了它通过禁用跟踪
  • @Cookie:你所描述的正是你被告知不能发生的事情。当对象被序列化时,它不能被修改。以任何方式。完全没有。没有人。

标签: c++ serialization boost


【解决方案1】:

想象一下用于序列化的对象如下:

从A开始,使用栈来判断我们还需要访问什么:

  1. 访问A
  2. 推送B,C
  3. 流行并访问C
  4. 按“D”
  5. 其他东西会删除 B 并将其替换为 D
  6. 弹出并访问“D”
  7. 弹出并访问标记为B,但现在也确实是D

然后您的情况将被错误地捕获为共享参考。如果 anything 可以更改 any 的指针,或者它们在序列化开始和结束之间指向的对象,那么您将获得不一致的状态。 p>

【讨论】:

  • 我从未见过用于指代您所描述的“虚假共享”。这不是一场常规的、普通的数据竞赛吗?
  • @Luc - 是的,但 OP 称其为错误共享(以及“错误地被捕获为共享引用”),所以我试图展示他们所询问的内容可能只是一个数据竞赛。我现在改写了它,以更准确地匹配他们的描述,并避免我对“虚假分享”一词的糟糕、过度使用
【解决方案2】:

简短回答:是的,会发生这种情况。

原因是(从其他答案和 cmets 可以得出结论)这是对序列化库的用途的轻微滥用。因此,如果在一天的过程中使用 boost 序列化来记录对象(例如,并非所有对象在序列化开始时都在内存中),并且对象恰好具有相同的地址,那么它们将被错误地共享。这发生在共享指针上,但也发生在常规指针上(据我所知)。

要解决此问题,请避免使用指针,或关闭跟踪。如果您关闭跟踪,并且仍然序列化共享指针(我目前正在这样做,尽管这可能并不理想),boost 中的几个硬编码检查会抱怨跟踪被关闭。为了解决这个问题,我破解了 boost 头文件的本地副本(并且必须在每次用于编译的更新和系统上都这样做)(尽管这很简单,编译器指向正确的行,并且它们被清楚地记录在案) .如果您可以选择在没有指针的情况下工作,那么您就省去了这个麻烦。

除此之外,日志记录工作非常出色,所以不要因为使用 boost 序列化而被关闭(正如上面的一些 cmets 所建议的那样)。

要在对象到达时记录它们,只需使用 void Log(Msg* msg) {ar & NVP(msg);} 并按照以下方式读取它们:

Msg* Read() {
    Msg* msg(0); 
    try {ar & NVP(msg);}
    catch (boost::archive::archive_exception const&) { }
    return msg; 
}

你会调用上面的Read函数,直到返回的指针是一个NULL指针,然后你就知道日志已经完成了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-21
    • 2014-07-01
    • 2015-02-13
    相关资源
    最近更新 更多