c++ - 在抛出 'std::system_error' 的实例后调用终止
问题描述
当我std::call_once
在 Linux 版本 2.6.36 中使用时,它会出错:
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;
}
解决方案
静态链接和动态链接之间存在主要区别。前者仅链接.a
解析当前未解析符号的目标文件,而.so
无论如何都链接共享库(除非-Wl,--as-needed
使用链接器选项)。
碰巧的是,GNU C++ 标准库std::call_once
通过检查是否pthread_create
可以解析来检查应用程序是否是多线程的。由于您的代码没有调用pthread_create
或std::thread
使用非默认构造函数,因此静态链接-pthread
不会链接 in 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
std::call_once
另一个修复是使用-Wl,--undefined=pthread_create,--undefined=pthread_cancel
链接器命令行选项,它不需要更改源代码。
请注意,在现代世界中,使用-lpthread
既不是必要的,也不是充分的。
推荐阅读
- lua - ZeroBrane 远程调试嵌入式脚本
- linux - 我可以将用户添加到 Google Cloud Platform 中的 www-data 组吗?
- python-3.x - 评估具有值的变量的正确方法是什么?
- markdown - 如何用 org-mode 格式表示要由 Pandoc 导出到 Powerpoint 的两列
- javascript - JavaScript 中这个特性的名称是什么?
- javascript - 如何从回调函数内部寻址 Vue.js 组件中的方法?
- rust - 如何避免在不同的匹配臂中借用 Vec 两次作为可变参数?
- excel - 添加另一个 For 循环,以便在保存文件之前添加另一个工作表数据
- c# - Automapper 子属性映射
- scala - 使用 Spray Json 解析超过 22 个字段,无需嵌套案例类