眠りネ*_*ネロク 6 c++ multithreading c++11 stdthread
以下文本摘自《C++ 标准库:教程和参考》第二版一书中的18.2.1 \xe2\x80\xa0部分:
\n\n\n但请注意,生命周期问题也适用于全局和静态对象,因为当程序退出时,分离的线程可能仍在运行,这意味着它可能会访问已销毁或正在销毁的全局或静态对象。不幸的是,这会导致未定义的行为。
\n
据我了解,所有分离的线程将在main()结束时终止。
因此,我怀疑这种行为的原因是全局和静态对象的实际销毁顺序对于分离线程的终止而言是未指定的,即,它可能发生在分离线程终止之前、期间或之后。
\n如果对此事有任何进一步的澄清,我们将不胜感激。
\n\xe2\x80\xa0更具体地说:在标题“谨防分离线程”下的小节中下的小节中。
\n所有静态初始化或延迟初始化的内容(例如,进入其包含块的块范围静态变量)都会在正常程序终止期间取消初始化 - 通过main()返回或调用exit().
问题不在于线程终止的顺序,而在于根本没有努力阻止它们。相反,(可能仍在运行的)线程的收割工作被委托给操作系统,以便在进程终止时进行排序。
实际上,强制终止线程(分离或其他方式)对于实现来说确实很困难。抛开其他事情不说,这是不可预测行为的一个秘诀,因为这些线程几乎总是在同步对象或系统调用上被阻塞,并持有资源(你好死锁!)。另一方面,Posix-Threads 不提供 API 来执行此操作。毫不奇怪,线程需要从其线程函数返回才能退出。
返回和进程终止之间存在有限的时间段main(),其中运行时执行静态去初始化(与初始化的顺序严格相反)以及用 注册的任何内容atexit(),在此期间任何现有线程仍然可以运行。在大型程序中,这个时间可能很重要。
如果这些线程中的任何一个碰巧访问静态初始化的对象,这当然是未定义的行为。
最近,我花了相当多的时间来追踪一个大型 iOS 应用程序中的一系列崩溃问题,该应用程序主要使用 C++。
崩溃的代码看起来很像这样,崩溃的根源在std::set<T>::find(const T&)
bool checkWord(const std::string &w)
{
static std::set<std::string> tags{"foo", "bar"};
return (tags.find(w) != tags.end());
}
Run Code Online (Sandbox Code Playgroud)
与此同时,在主线程上,调用了exit()堆栈中的几个函数。
iOS 和 macOS 应用程序使用 Grand Central Dispatch/libdispatch 进行大量多线程处理,事实证明,main()退出后不仅线程仍在运行,而且作业也从后台调度队列执行。
我怀疑许多其他系统上也会出现类似的情况。
除了避免块范围静态以支持不需要初始化的数据之外,我没有找到解决该问题的非常好的解决方案。
| 归档时间: |
|
| 查看次数: |
1382 次 |
| 最近记录: |