我可以使 Meyers 单例在分叉的 child 进程中重新初始化吗?

Can I cause a Meyers singleton to reinitialize in forked child processes?

假设我有一个 meyers 单身人士

Data& get() {
  static Data data = initialization_work();
  return data;
}

已在 parent 进程中使用和初始化。然后我 fork(2) 一个 child 进程,在 child 进程中 data 可能需要不同(即,我希望 initialization_work() 第一次重新运行get() 在 child).

中调用

首先,data会在分叉的child中自动重新初始化吗?我的怀疑是不,基于我对 linux 的平庸知识(分叉 child VA space 是映射到物理内存 copy-on-write 的 parent 的副本,所以我假设 child 进程将看到 data 已经初始化并且不会重做 initialization_work())和其他几个问题(C static variables and linux forkC++ static variable and multiple processes).

其次,如果data 默认情况下不会在child中重新初始化,有没有办法在第一次[=]时强制重新初始化33=] 呼叫 get()?如果没有,我可以尝试找出一些其他模式(我非常感谢任何关于哪种模式可能适合这个用例的建议)。

First, will data automatically be reinitialized in the forked child? My suspicion is no

为什么只是怀疑?事实上,什么都不会被初始化。正如@MartinYork 提到的那样 - 您会得到一份原始流程的副本。这就是分叉的魔力——无需初始化世界。 parent 和 child 都(几乎)仅根据 fork() 调用的 return 值继续采取不同的行动。

Second, if data will not be reinitialized in the child by default, is there a way to force reinitialization the first time the child calls get()?

这与询问在原始进程中强制重新初始化单例是同一个问题。现在,当然有办法...

  • 你得到了 non-const 对 data 的引用,对吧?好吧,你可以 destroy it explicitly, then use placement-new 在那个地址上。我...几乎可以肯定这是合法的。

  • @BenVoigt 对上述内容的巧妙替代:使用 std::optional<Data> singleton. It's still a sort-of-a-singleton, but you can assign nullopt to it, for destruction, then construct a new Data in place with std::optional::emplace.

  • 更改 class' 代码以将 data 变量放置在更显眼的位置。

  • 放弃单例模式。你不太可能真的需要它。观看:

    Retiring the Singleton Pattern: Concrete Suggestions for What to use Instead
    Peter Muldoon 在 CppCon'20 上的演讲。