lundi 24 février 2020

reason for unknown exception in promise without lpthread

Note that this question has an 'answer' at here and here, but my question is not on how to get rid of the error, but why this error occurs.

Consider the following code:

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);
}

This code throws an exception:

$ 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)

The solution is to pass -lpthread on command line:

$ g++ -g -std=c++1z -lpthread main.cpp
$ ./a.out
42

Now, I am used to get a linking error when I don't link with a required library. This is the first time I get a runtime error.

When you run the version (without lpthread) under gdb, this is the stack trace you get (redacted some of it):

#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

So it is something to do with call_once. Curious on why that manifests as a runtime error instead of link time.

Aucun commentaire:

Enregistrer un commentaire