请注意,这个问题在here和here处都有一个“答案”,但我的问题不是关于如何消除错误,而是为什么会发生此错误。
考虑以下代码:
include <cstdio>
#include <future>
int main() {
std::promise<int> promise;
auto future = promise.get_future();
promise.set_value(42);
auto result = future.get();
printf("%d\n", result);
}
此代码引发异常:
$ g++ -g -std=c++1z main.cpp
$ ./a.out
terminate called after throwing an instance of 'std::system_error'
what(): Unknown error -1
Aborted (core dumped)
解决方案是在命令行上传递
-lpthread
:$ g++ -g -std=c++1z -lpthread main.cpp
$ ./a.out
42
现在,当我不链接所需的库时,我经常会遇到链接错误。这是我第一次遇到运行时错误。
当您在gdb下运行版本(不使用
lpthread
)时,这是您将获得的堆栈跟踪(其中部分已删除):#5 0x00007ffff7aa6ef3 in __cxxabiv1::__cxa_throw (obj=obj@entry=0x61ad00,
tinfo=tinfo@entry=0x7ffff7dce6b0 <typeinfo for std::system_error>,
dest=dest@entry=0x7ffff7ad02b0 <std::system_error::~system_error()>)
at /tmp/tmp.kmkSDUDFn8/build/../gcc-9.1.0/libstdc++-v3/libsupc++/eh_throw.cc:95
#6 0x00007ffff7a9d0ec in std::__throw_system_error (__i=-1)
at /tmp/tmp.kmkSDUDFn8/build/x86_64-pc-linux-gnu/libstdc++-v3/include/ext/new_allocator.h:89
#7 0x000000000040240f in std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) (__once=..., __f=
@0x7fffffffdd80: (void (std::__future_base::_State_baseV2::*)(class std::__future_base::_State_baseV2 * const, class std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()> *, bool *)) 0x40200c <std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*)>, __args#0=@0x7fffffffdd78: 0x61ac30, __args#1=@0x7fffffffdd70: 0x7fffffffddf0,
__args#2=@0x7fffffffdd68: 0x7fffffffdd67) at /.../include/c++/9.1.0/mutex:697
#8 0x0000000000401e5d in std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) (this=0x61ac30, __res=..., __ignore_failure=false)
at /.../include/c++/9.1.0/future:401
因此,它与
call_once
有关。好奇为什么这表现为运行时错误而不是链接时间。 最佳答案
GNU libc
提供了Pthread函数的替代实现,因此即使没有-pthread
,链接也可以成功。参见is pthread in glibc.so implemented by weak symbol to provide pthread stub functions?和Why glibc and pthread library both defined same APIs?
GNU C++标准 std::call_once
可以
int __e = __gthread_once(&__once._M_once, &__once_proxy);
__gthread_once
是:static inline int
__gthread_once (__gthread_once_t *__once, void (*__func) (void))
{
if (__gthread_active_p ())
return __gthrw_(pthread_once) (__once, __func);
else
return -1;
}
GNU C++标准库在运行时检测
pthread
函数中是否可用__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). */
作为引用答案的状态,在编译和链接多线程程序时都应该使用
-pthread
选项。 -lpthread
不够,因为它没有定义某些代码可能需要的_REENTRANT
宏:$ diff <(g++ -E -dD -xc++ /dev/null) <(g++ -E -dD -xc++ -pthread /dev/null)
289a290
> #define _REENTRANT 1
关于c++ - 没有lpthread的Promise中出现未知异常的原因,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60381333/