抛出“std::system_error”实例后调用终止

问题描述 投票:0回答:2

当我在 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;
}
c++ multithreading c++11 libstdc++
2个回答
7
投票

静态链接和动态链接之间存在重大区别。前者仅链接来自

.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 *) &GTHR_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
既不是必要的,也不是充分的


0
投票

我遇到了同样的问题,我通过从编译命令行中删除

-static
来修复它,这与
mutex
冲突。 我希望它有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.