C++ 不带lpthread的promise中出现未知异常的原因

C++ 不带lpthread的promise中出现未知异常的原因,c++,c++11,C++,C++11,请注意,这个问题在和处有一个“答案”,但我的问题不是如何消除错误,而是为什么会发生错误 考虑以下代码: 包括 #包括 int main(){ 承诺; 自动未来=承诺。获取未来(); 承诺。设定_值(42); 自动结果=future.get(); printf(“%d\n”,结果); } 此代码引发异常: $ g++ -g -std=c++1z main.cpp $ ./a.out terminate called after throwing an instance of 'std::syst

请注意,这个问题在和处有一个“答案”,但我的问题不是如何消除错误,而是为什么会发生错误

考虑以下代码:

包括
#包括
int main(){
承诺;
自动未来=承诺。获取未来();
承诺。设定_值(42);
自动结果=future.get();
printf(“%d\n”,结果);
}
此代码引发异常:

$ 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 0x00007FF7AA6EF3 in uuuuCxAbiv1::uuuCxA_Uthrow(obj=obj@entry=0x61ad00,
锡箔=tinfo@entry=0x7ffff7dce6b0,
目的地=dest@entry=0x7ffff7ad02b0)
at/tmp/tmp.kmkSDUDFn8/build/。/gcc-9.1.0/libstdc++-v3/libsupc++/eh_-throw.cc:95
#标准中的6 0x00007FF7A9D0EC:\uuuuu抛出\uu系统错误(\uuuuu i=-1)
at/tmp/tmp.kmkSDUDFn8/build/x86_64-pc-linux-gnu/libstdc++-v3/include/ext/new_allocator.h:89
#7 0x000000000040240f在std::call_once(std::once_标志和,void(std::_未来_基::_状态_基v2::*&&&)(std::function*,bool*),std:_未来_基::_状态_基v2*&,std::function*&,bool*&)(u once=…,bool*&)=
@0x7FFFFFDD80:(void(std:uuu future u base:::*)(类std:uu future u base:::u State u baseV2*const,类std::function*,bool*)0x40200c,uuu args#0=@0x7fffffffdd78:0x61ac30,uu args#1=@0x7fffffffdd70:0x7FFFFFDDF0,
__args#2=@0x7fffffffdd68:0x7fffffffdd67)位于/../include/c++/9.1.0/mutex:697
#标准中的8 0x0000000000401e5d::uuu future_base::_State_baseV2::_M_set_result(标准::函数,布尔)(this=0x61ac30,uuuu res=…,uu忽略_failure=false)
at/../include/c++/9.1.0/future:401

因此,它与
一次调用\u
有关。想知道为什么这会表现为运行时错误而不是链接时间。

GNU
libc
提供了Pthread函数的替代实现,因此即使没有
-Pthread
,链接也会成功。看到和

GNU C++标准做< /P> 是:

GNU C++标准库在运行时检测函数是否为代码> pTox< /Cord>库实现。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不够,因为它没有定义某些代码可能需要的可重入的宏:

$ diff <(g++ -E -dD -xc++ /dev/null) <(g++ -E -dD -xc++ -pthread /dev/null)
289a290
> #define _REENTRANT 1

$diff您应该使用
-pthread
进行编译和链接,而不是
-lphread
()@Mat
-pthread
也可以工作。但问题是为什么我们在运行时而不是在链接时出现此错误。我很好奇,理论上是否有可能在编译/链接时而不是在运行时检测到此错误?@skgbanga
glibc
提供了Pthread函数的替代实现,因此即使没有
-Pthread
,链接也会成功。看到和
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;
}
/* 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).  */
$ diff <(g++ -E -dD -xc++ /dev/null) <(g++ -E -dD -xc++ -pthread /dev/null)
289a290
> #define _REENTRANT 1