8

在某些时候,我记得读到直到main()的第一行才能安全地创建线程,因为编译器会插入特殊的代码来在静态初始化时间内运行线程工作。所以如果你有一个全局对象在构建时创建一个线程,你的程序可能会崩溃。但是现在我找不到原文,我很好奇这个限制有多严格 - 这是标准严格遵守的吗?在大多数编译器上它是真的吗?它会在C++ 0x中保持真实吗?一个符合标准的编译器是否有可能自己创建静态初始化程序多线程? (例如,检测到两个全局对象不相互接触,并在单独的线程上初始化它们以加速程序启动)在静态初始化期间可以安全地创建线程吗?

编辑:为了澄清,我试图至少了解实现是否真的显着不同在这方面,或者如果这是伪标准的东西。例如,在技术上,该标准允许对属于不同访问说明符(public/protected /等)的成员进行混洗。但没有编译器我知道实际上是否这样做。

+0

“这是严格按照标准真正的” - C++ 03标准对于线程主题没有什么可说的。当前行为所关注的地方是POSIX(它当然是* a *标准,而不是*标准),MSDN,Boost或其他针对编译器,平台和线程API的特定于实现的文档使用。 – 2009-09-18 15:25:31

回答

6

你说的不是严格的语言,而是C运行时间库(CRT)。
首先,如果您在Windows上使用本机调用(如CreateThread())创建线程,则可以在任何需要的位置执行此操作,因为它可以在不干涉CRT的情况下直接进入操作系统。
您通常使用的其他选项是使用_beginthread(),它是CRT的一部分。使用_beginthread()有一些优点,例如具有线程安全的errno。 Read more about this here。如果要使用_beginthread()创建线程,则可能会出现一些问题,因为_beginthread()所需的初始化可能不适用。

这涉及到一个更为普遍的问题,即在main()之前发生了什么以及按什么顺序。基本上你有程序的入口点功能,在使用Visual Studio处理main()之前需要处理所有需要发生的事情,你可以看看CRT中的这段代码,并找出自己究竟发生了什么。最简单的方法是停止代码中的断点,然后查看堆栈帧main()

+0

谢谢,这给了我一些有关使用MSVC的Windows情况的想法。我仍然对其他平台感到好奇,它并没有真正回答它是否在Windows上安全(_beginthread()实际上是否依赖于任何可能还没有发生的初始化?)。 – 2009-09-18 18:22:50

+0

我希望我也知道这一点。文档似乎没有提及它。 – shoosh 2009-09-18 19:40:15

2

底层问题是Windows对DllMain中可以执行和不能执行的操作的限制。特别是,你不应该在DllMain中创建线程。静态初始化通常发生在DllMain中。然后在逻辑上遵循静态初始化过程中不能创建线程。

+1

但是请注意:'在进程启动和DLL初始化例程期间,可以创建新线程,但是直到http://msdn.microsoft的进程完成DLL初始化才开始执行。com/en-us/library/ms682453%28v = VS.85%29.aspx – 2011-07-16 21:29:49

+0

公平点,没有见过。请注意,该注释特别适用于'CreateThread',但_beginthreadex没有这个例外。 – MSalters 2011-07-18 08:01:53

0

据我所知,通过阅读C++ 0x/1x草案,在main()之前启动一个线程是很好的,但仍然受到静态初始化的正常陷阱。一致性实现必须确保在任何静态或线程构造函数执行之前执行线程初始化的代码。

相关问题