C++ 查明静态初始化是否已结束 简略问题(Y)

C++ 查明静态初始化是否已结束 简略问题(Y),c++,visual-c++,static-initialization,C++,Visual C++,Static Initialization,假设您需要从一个函数中知道该函数是否作为静态对象初始化的一部分被调用。是否有标准或特定于平台的方法来实现这一点 背景故事(X) 我深入了解了许多应用程序使用的DLL的源代码。此DLL公开了一个Init函数,此函数应构造一个boost::asio::daildate\u计时器,供以后使用(但DLL可以在降级模式下不使用它的情况下工作) 问题是在初始化静态对象(DLL加载时间)期间无法构造计时器 当然,每个人和他们的cat调用Init(是的,多次!),包括我不想编辑的源代码中的静态构造函数,因此需要

假设您需要从一个函数中知道该函数是否作为静态对象初始化的一部分被调用。是否有标准或特定于平台的方法来实现这一点

背景故事(X) 我深入了解了许多应用程序使用的DLL的源代码。此DLL公开了一个
Init
函数,此函数应构造一个
boost::asio::daildate\u计时器
,供以后使用(但DLL可以在降级模式下不使用它的情况下工作)

问题是在初始化静态对象(DLL加载时间)期间无法构造计时器

当然,每个人和他们的cat调用
Init
(是的,多次!),包括我不想编辑的源代码中的静态构造函数,因此需要检测这种情况并退出


在实用主义克服了厌恶之后,我最终在调用堆栈中找到了
wWinMain
,并推断静态初始化已经结束。这很糟糕,无法处理动态加载的二进制文件,谢天谢地,这超出了我的特定案例的范围。我真希望有一个更干净的方法。

现在,让我们假设您的DLL有两个入口点:
Init
frobnite

Init
实际上什么都不做
frobnite
检查全局布尔值,以确定DLL是否真正初始化过。如果不是,它首先进行真正的初始化,这也设置了I've-really-initialized标志,然后才实际进行蛙鸣

很可能,您有更多的入口点(
Frobnicate2
frobNicate3
,…),因此您必须将此逻辑添加到每个入口点中。这很乏味,但并非前所未闻。当时,我们必须编写自己的延迟加载机制,这些机制非常相似。当然,我们当时只提供了DLL中的C风格接口,而不是方法名称混乱的C++风格对象,但它必须仍然是可以实现的

这假设可以将初始化延迟到第一个非
Init
调用进入DLL。这可能是一个好的假设,也可能不是

其他不切实际的想法:

  • 找到一种检测装载机锁的方法(而不是实际的死锁)。如果在调用
    Init
    时保持加载程序锁,则这是一个“太早”的时刻。这与你在堆栈中的查找结果一致-<代码> WiMeNe/COD>解决方案。
  • Init
    调用得太快时,做一些确保死锁的事情,并让您的客户机修复他们该死的代码
  • 创建一个隐藏的“仅邮件”窗口并向其发布邮件。假设客户机是一个传统的GUI应用程序,它将在同一个线程上发送消息,那么,当您收到消息时,应该可以安全地进行真正的初始化(希望不会太晚)

您是否尝试在DLLMain中的适当时间设置全局变量以指示静态初始化已完成?@JustinFinnerty他正在编写一个库,他无法控制
main()
@JustinFinnerty问题明确指出他的
Init()
方法是从静态构造函数调用的。是否将
截止时间计时器的创建推迟到第一次需要时才可行?或者当调用其他(非Init)函数时,但需要在截止时间之前\u计时器?在调用Init后1秒、2秒或42秒创建一个一次性计时器并不是100%可靠的,所以这是错误的。啊,没错,因为
SetTimer
位于
User32.dll中,在加载锁定期间不能调用它。DLL的用户是否会调用一些其他函数或函数的小集合,例如Create或Open类型的函数,这些函数不经常调用,但在某种程度上是必需的?如果尚未创建计时器,则可以创建计时器。可以确认。。。发布了一个带有两阶段初始化的DLL,其中每个入口点都以
if(init\u haves\u called())
开头。如果在另一个DLL的初始化代码中调用了Frobnite,那么问题仍然存在。@Justin Finnerty:是的,这是一个没有赢的情况。客户端永远不应该从静态初始化方法调用任何东西,但他们确实调用了,我们正在尽最大努力防止它破坏东西。如果他们在静态初始化中做“真正的工作”,那么所有的希望都可能破灭。