【问题标题】:Can threads be safely created during static initialization?在静态初始化期间可以安全地创建线程吗?
【发布时间】:2010-11-29 12:43:47
【问题描述】:

在某些时候,我记得读到在 main() 的第一行之前无法安全地创建线程,因为编译器会插入特殊代码以使线程在静态初始化期间运行。因此,如果您有一个在构造时创建线程的全局对象,您的程序可能会崩溃。但是现在我找不到原始文章了,我很好奇这是一个多么严格的限制——按标准严格来说是真的吗?大多数编译器都是这样吗?在 C++0x 中它会保持不变吗?符合标准的编译器是否可以使静态初始化本身成为多线程的? (例如检测两个全局对象不相互接触,并在不同的线程上初始化它们以加速程序启动)

编辑:为了澄清,我试图至少了解实现在这方面是否真的有很大差异,或者它是否是伪标准的东西。例如,从技术上讲,该标准允许改组属于不同访问说明符(公共/受保护/等)的成员的布局。但是我所知道的编译器实际上没有这样做。

【问题讨论】:

  • “按照标准严格来说是真的吗”——C++03 标准对线程的主题没有什么可说的。就当前行为而言,需要查看的地方是 POSIX(这当然是 a 标准,只是不是 the 标准)、MSDN、Boost 或其他特定于实现的您使用的编译器、平台和线程 API 的文档。

标签: c++ multithreading c++11 standards-compliance static-initialization


【解决方案1】:

您所说的并不是严格意义上的语言,而是 C 运行时库 (CRT)。
首先,如果您在 Windows 上使用诸如 CreateThread() 之类的本机调用创建线程,那么您可以在任何您喜欢的地方执行此操作,因为它直接进入操作系统,无需 CRT 干预。
您通常拥有的另一个选项是使用 _beginthread(),它是 CRT 的一部分。使用_beginthread() 有一些优点,例如具有线程安全的errno。 Read more about this here。如果您要使用_beginthread() 创建线程,可能会出现一些问题,因为_beginthread() 所需的初始化可能没有到位。

这涉及到一个更普遍的问题,即在main() 之前究竟发生了什么以及以什么顺序发生。基本上,您拥有程序的入口点功能,该功能使用 Visual Studio 处理 main() 之前需要发生的所有事情,您实际上可以查看 CRT 中的这段代码,并亲自了解那里到底发生了什么。获取该代码的最简单方法是在代码中停止断点并查看main()之前的堆栈帧

【讨论】:

  • 谢谢,这让我对使用 MSVC 的 Windows 上的情况有所了解。尽管如此,我仍然对其他平台感到好奇,它并没有真正回答它在 Windows 上是否安全(_beginthread() 实际上是否依赖于任何可能尚未发生的初始化?)。
  • 我希望我也知道这一点。文档似乎没有提到它。
【解决方案2】:

根本问题是 Windows 限制了您在 DllMain 中可以做什么和不可以做什么。特别是,您不应该在 DllMain 中创建线程。静态初始化通常发生在 DllMain 中。那么从逻辑上讲,你不能在静态初始化期间创建线程。

【讨论】:

  • 但请注意:During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is done for the process from msdn.microsoft.com/en-us/library/ms682453%28v=VS.85%29.aspx
  • 公平点,没见过。请注意,该评论专门适用于CreateThread,但_beginthreadex 没有此例外。
【解决方案3】:

据我阅读 C++0x/1x 草案可知,在 main() 之前启动一个线程是可以的,但仍会受到静态初始化的正常陷阱的影响。符合要求的实现必须确保初始化线程的代码在任何静态或线程构造函数之前执行。

【讨论】:

    猜你喜欢
    • 2012-05-22
    • 2010-10-27
    • 1970-01-01
    • 2010-12-30
    • 2010-12-31
    • 1970-01-01
    • 2013-09-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多