gpt4 book ai didi

c++ - 没有lpthread的promise中未知异常的原因

转载 作者:行者123 更新时间:2023-12-01 14:48:40 28 4
gpt4 key购买 nike

请注意,此问题在 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/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com