静态初始化期间可以安全地创建线程吗?
在某些时候,我记得读到直到 main() 的第一行才能安全地创建线程,因为编译器插入特殊代码以使线程在静态初始化期间运行。因此,如果您有一个在构造时创建线程的全局对象,您的程序可能会崩溃。但现在我找不到原文了,我很好奇这个限制有多强——按照标准严格来说是真的吗?大多数编译器都是这样吗?它在 C++0x 中仍然如此吗?符合标准的编译器是否可以使静态初始化本身多线程化? (例如,检测两个全局对象不相互接触,并在单独的线程上初始化它们以加速程序启动)
编辑:为了澄清,我试图至少了解实现在这方面是否确实存在显着差异,或者如果它是伪标准的东西。例如,从技术上讲,该标准允许打乱属于不同访问说明符(公共/受保护/等)的成员的布局。但据我所知,没有编译器真正做到这一点。
At some point I remember reading that threads can't be safely created until the first line of main(), because compilers insert special code to make threading work that runs during static initialization time. So if you have a global object that creates a thread on construction, your program may crash. But now I can't find the original article, and I'm curious how strong a restriction this is -- is it strictly true by the standard? Is it true on most compilers? Will it remain true in C++0x? Is it possible for a standards conforming compiler to make static initialization itself multithreaded? (e.g. detecting that two global objects don't touch one another, and initializing them on separate threads to accelerate program startup)
Edit: To clarify, I'm trying to at least get a feel for whether implementations really differ significantly in this respect, or if it's something that's pseudo-standard. For example, technically the standard allows for shuffling the layout of members that belong to different access specifiers (public/protected/etc.). But no compiler I know of actually does this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您所说的并不是严格意义上的语言,而是 C 运行时库 (CRT) 中的内容。
首先,如果您在 Windows 上使用诸如
CreateThread()
之类的本机调用创建线程,那么您可以在任何您想要的地方执行此操作,因为它会直接进入操作系统,无需 CRT 的干预.通常的另一个选择是使用
_beginthread()
,它是 CRT 的一部分。使用_beginthread()
有一些优点,例如具有线程安全的 errno。 在此处了解有关此内容的更多信息。如果您要使用_beginthread()
创建线程,则可能会出现一些问题,因为_beginthread()
所需的初始化可能未到位。这涉及到一个更普遍的问题,即
main()
之前到底发生了什么以及按什么顺序发生。基本上,您拥有程序的入口点函数,它可以使用 Visual Studio 处理main()
之前需要发生的所有事情,您实际上可以查看 CRT 中的这段代码并亲自找出答案那里到底发生了什么。访问该代码的最简单方法是停止代码中的断点并查看main()
之前的堆栈帧What you're talking about isn't strictly in the language but in the C Run Time Library (CRT).
For a start, if you create a thread using a native call such as
CreateThread()
on windows then you can do it anywhere you'd like because it goes straight to the OS with no intervention of the CRT.The other option you usually have is to use
_beginthread()
which is part of the CRT. There are some advantages to using_beginthread()
such as having a thread-safe errno. Read more about this here. If you're going to create threads using_beginthread()
there could be some issues because the initializations needed for_beginthread()
might not be in place.This touches on a more general issue of what exactly happens before
main()
and in what order. Basically you have the program's entry point function which takes care of everything that needs to happen beforemain()
with Visual Studio you can actually look at this piece of code which is in the CRT and find out for yourself what exactly's going on there. The easyest way to get to that code is to stop a breakpoint in your code and look at the stack frames beforemain()
根本问题是 Windows 对 DllMain 中可以执行的操作和不能执行的操作进行了限制。特别是,您不应该在 DllMain 中创建线程。静态初始化通常发生在 DllMain 中。那么从逻辑上来说,你不能在静态初始化期间创建线程。
The underlying problem is a Windows restriction on what you can and cannot do in DllMain. In particular, you're not supposed to create threads in DllMain. Static initialization often happens from DllMain. Then it follows logically that you can't create threads during static initialization.
据我从阅读 C++0x/1x 草案来看,在
main()
之前启动线程是可以的,但仍然会遇到静态初始化的常见陷阱。符合要求的实现必须确保初始化线程的代码在任何静态或线程构造函数之前执行。As far as I can tell from reading the C++0x/1x draft, starting a thread prior to
main()
is fine, but still subject to the normal pitfalls of static initialization. A conforming implementation will have to make sure the code to intialize threading executes before any static or thread constructors do.