在抛出 'std::system_error' 的实例后调用终止
Posted
技术标签:
【中文标题】在抛出 \'std::system_error\' 的实例后调用终止【英文标题】:terminate called after throwing an instance of 'std::system_error'在抛出 'std::system_error' 的实例后调用终止 【发布时间】:2020-12-17 06:24:48 【问题描述】:当我在 Linux 版本 2.6.36 中使用 std::call_once
时,它会出错:
terminate called after throwing an instance of 'std::system_error'
what(): Unknown error -1
Aborted
编译命令:
mipsel-buildroot-linux-uclibc-g++ callonce.cpp -o callonce -static -lpthread
我的代码:
#include <iostream>
#include <mutex>
using namespace std;
int main()
cout << "Hello world" << std::endl;
static once_flag of;
call_once(of,[]);
return 0;
【问题讨论】:
我可以重现这个,但如果我用简单的-pthread
替换-static -lpthread
,那么它就可以工作。省略-pthread
,或使用-static -pthread
,它会再次崩溃。 Try on Godbolt.
我尝试了 -pthread、-lpthread 和 -static 的四种组合: -pthread ...worked; -lpthread ...工作; -static -pthread ...崩溃; -static -lpthread ...崩溃;那么,-static 似乎有问题?
gcc 10.2 barfs 但gcc trunc 似乎处理得很好。
...但是这个“问题”更多的是当前状态下的陈述。为了让某人能够给出答案,您必须提出一个问题。如果问题是“gcc 版本 x 中是否存在错误?”,那么答案很可能是“是”。
嗯,-lpthread
一个人在我自己的系统上崩溃,但在 Godbolt 上工作。
【参考方案1】:
静态链接和动态链接之间存在主要区别。前者仅链接来自 .a
的目标文件中的链接,这些文件解析了当前未解析的符号,而共享库 .so
无论如何都被完整链接(除非使用 -Wl,--as-needed
链接器选项)。
碰巧的是,GNU C++ 标准库std::call_once
通过检查pthread_create
是否可以解析来检查应用程序是否是多线程的。由于您的代码没有使用非默认构造函数调用pthread_create
或std::thread
,因此静态链接-pthread
不会链接pthread_create
,因此std::call_once
失败。检查是通过调用__gthread_active_p
函数来完成的:
/* For a program to be multi-threaded the only thing that it certainly must
be using is pthread_create. However, there may be other libraries that
intercept pthread_create with their own definitions to wrap pthreads
functionality for some purpose. In those cases, pthread_create being
defined might not necessarily mean that libpthread is actually linked
in.
For the GNU C library, we can use a known internal name. This is always
available in the ABI, but no other library would define it. That is
ideal, since any public pthread function might be intercepted just as
pthread_create might be. __pthread_key_create is an "internal"
implementation symbol, but it is part of the public exported ABI. Also,
it's among the symbols that the static libpthread.a always links in
whenever pthread_create is used, so there is no danger of a false
negative result in any statically-linked, multi-threaded program.
For others, we choose pthread_cancel as a function that seems unlikely
to be redefined by an interceptor library. The bionic (android) C
library does not provide pthread_cancel, so we do use pthread_create
there (and interceptor libraries lose). */
#ifdef __GLIBC__
__gthrw2(__gthrw_(__pthread_key_create),
__pthread_key_create,
pthread_key_create)
# define GTHR_ACTIVE_PROXY __gthrw_(__pthread_key_create)
#elif defined (__BIONIC__)
# define GTHR_ACTIVE_PROXY __gthrw_(pthread_create)
#else
# define GTHR_ACTIVE_PROXY __gthrw_(pthread_cancel)
#endif
static inline int
__gthread_active_p (void)
static void *const __gthread_active_ptr
= __extension__ (void *) >HR_ACTIVE_PROXY;
return __gthread_active_ptr != 0;
一个解决方法是 #include <pthread.h>
并在 main
函数的顶部添加一两行:
static_cast<void>(pthread_create);
static_cast<void>(pthread_cancel);
这会导致对pthread_create
和pthread_cancel
的未定义引用,并使这些函数中的-static -pthread
从静态库链接到您的应用程序,这使得__gthread_active_p
函数返回1
,进而启用@987654342 @上班。
另一个修复方法是使用-Wl,--undefined=pthread_create,--undefined=pthread_cancel
链接器命令行选项,它不需要更改源代码。
请注意,在现代世界中使用-lpthread
is neither necessary nor sufficient。
【讨论】:
我明白了,我的演示终于成功了...非常感谢您的分享:) 顺便说一句,我有一个修复方法是使用 -Wl,--whole-archive -lrt -lpthread -Wl,--no-whole-archive,它适用于我的 Ubuntu-1604,但仍然在 mips32-linux 上崩溃以上是关于在抛出 'std::system_error' 的实例后调用终止的主要内容,如果未能解决你的问题,请参考以下文章
在抛出“std::system_error”线程池的实例后调用终止
xmake经验总结1:解决c++ future/promise抛出std::system_error的问题
xmake经验总结1:解决c++ future/promise抛出std::system_error的问题
xmake经验总结1:解决c++ future/promise抛出std::system_error的问题