c++ - 分离线程访问全局或静态对象

标签 c++ multithreading c++11 stdthread

以下文本摘自The C++ Standard Library: A Tutorial and Reference, 2nd Edition一书的第 18.2.1 节: p>

Note, however, that the lifetime problem also applies to global and static objects, because when the program exits, the detached thread might still run, which means that it might access global or static objects that are already destroyed or under destruction. Unfortunately, this would result in undefined behavior.

据我所知,所有分离的线程都将在 main() 结束时终止。

因此,我怀疑这种行为的原因是全局和静态对象的实际销毁顺序相对于分离线程的终止是未指定的,即它可能发生在之前,在分离的线程终止期间或之后。

如能进一步澄清此事,我们将不胜感激。


更具体地说:在标题小心分离线程下的小节中。

最佳答案

所有静态初始化或延迟初始化的东西(例如,进入包含 block 的 block 作用域静态变量)在正常程序终止期间都会被取消初始化 - 通过 main()返回或跟随调用 exit() .

问题与其说是线程终止的顺序,不如说是根本没有努力阻止它们。相反,(可能仍在运行的)线程的收获被委托(delegate)给操作系统,以在进程终止时进行排序。

实际上,实现强制终止线程(分离的或其他方式)真的很困难。撇开其他不谈,这是导致不可预测行为的秘诀,因为这些线程几乎总是被同步对象或系统调用阻塞,并持有资源(你好,死锁!)。另一方面,Posix-Threads 不提供这样做的 API。线程需要从其线程函数返回才能退出也就不足为奇了。

main() 之间有有限的时间段返回和进程终止,其中运行时执行静态取消初始化(严格按照与初始化顺序相反的顺序)以及用 atexit() 注册的任何内容,在此期间任何现存的线程仍然可以运行。在大型程序中,这个时间可能很重要。

如果这些线程中的任何一个碰巧访问了一个静态初始化的对象,这当然是未定义的行为

我最近花了相当多的时间来追踪一个包含大量 C++ 的大型 iOS 应用程序中的一系列崩溃。

崩溃的代码看起来很像这样,崩溃在 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());
}


与此同时,在主线程上,调用了exit()。堆栈中的几个函数。

iOS 和 macOS 应用程序使用 Grand Central Dispatch/libdispatch 进行大量多线程处理,事实证明,不仅线程在 main() 之后仍在运行。退出,但作业也在后台调度队列中执行。

我怀疑在许多其他系统上也会出现类似情况。

除了避免 block 作用域静态支持不需要初始化的数据外,我没有找到解决该问题的非常好的解决方案。

关于c++ - 分离线程访问全局或静态对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54297939/

相关文章:

c++ - vector 计数函数 C++

c++ - QuantLib C++ 库 - FixedRateBond 优惠券

c++ - Windows Phone 8.1 是否支持 select() 套接字函数?

c++ - 如何为运算符正确编写 R 值重载

c++ - 非常量对象的 vector 在基于范围的 for 循环中似乎被视为常量

c++ - 在 C++ 中使用 STL 算法的简单方法

c++ - 如何在 C++ 中为 PacMan 编写 map

python - 自定义锁线程python

multithreading - 如何将 Azure Durable Functions Orchestrator 中的逻辑移到另一个类中?

c# - 如何在 C# 中的 foreach 循环中使用多线程