56

After experiencing crashes when introducing nested calls of std::async in my real program, I was able to reproduce the problem in the following minimum example. It crashes often, but not always. Do you see anything what goes wrong, or is it a compiler or standard library bug? Note that the problem remains if get() calls to the futures are added.

#include <future>
#include <vector>

int main (int, char *[])
{
    std::vector<std::future<void>> v;
    v.reserve(100);
    for (int i = 0; i != 100; ++i)
    {
        v.emplace_back(std::async(std::launch::async, [] () {
            std::async(std::launch::async, [] { });
        }));
    }

    return 0;
}

I observe two different kinds of crashes: (in about every fifth run)

  • Termination with "This application has requested the Runtime to terminate it in an unusual way."
  • Termination after throwing an instance of 'std::future_error', what(): Promise already satisfied.

Environment:

  • Windows 7
  • gcc version 4.8.2 (i686-posix-dwarf-rev3, Built by MinGW-W64 project), as provided by Qt 5.3.2
  • Command line call: g++ -std=c++11 -pthread futures.cpp
  • Compiled and run on two independent machines

Option -pthread? Could it be that in my environment for some reason the option -pthread is silently not taken into account? I observe the same behavior with and without that option.

SebastianK
  • 3,582
  • 3
  • 30
  • 48
  • 1
    have you tried calling get() on each future before allowing the vector to go out of scope? – Richard Hodges Feb 19 '15 at 11:38
  • Yes, this doesn't change anything. – SebastianK Feb 19 '15 at 11:57
  • Have you run it on Linux or Unix with `strace` or `ltrace` already? – ott-- Feb 19 '15 at 12:09
  • 1
    @RichardHodges, all that would do is turn an implicit wait into an explicit one. – Jonathan Wakely Feb 19 '15 at 14:48
  • What kind of crash? Where does it crash? FWIW it's works fine with GCC 4.8.3 on GNU/Linux, but I've never tested GCC's `` on MinGW. – Jonathan Wakely Feb 19 '15 at 14:53
  • @JonathanWakely I edited the original question to answer your question. – SebastianK Feb 19 '15 at 15:10
  • 1
    Thanks. The first error looks like a generic, unhelpful Windows error (oh, unusual ... well I'll go and fix the unusual bits of code!) but the second is very strange and shouldn't be possible when using `std::async` – Jonathan Wakely Feb 19 '15 at 15:25
  • 8
    Since no one has said so outright, I'll comment that this is a well-formed conforming C++11 program. There's a bug (race) somewhere in the standard library implementation. – Casey Feb 19 '15 at 16:48
  • @Casey Thank you for the comment, I included it in the question. – SebastianK Feb 19 '15 at 16:57
  • 2
    @Casey, or the native platform runtime, or mingw runtime, since the same standard library implementation works fine on GNU/Linux. – Jonathan Wakely Feb 19 '15 at 18:51
  • confirming also works fine on apple clang with libc++. Looks like a library implementation problem. – Richard Hodges Feb 19 '15 at 19:24
  • 1
    Have you tried [filing a bug report](http://mingw.org/Reporting_Bugs) with the MinGW folks yet? – LThode Feb 20 '15 at 15:53
  • @JonathanWakely IIRC the first error is what happens when `abort()` is called. Of course, that's not very helpful either... – T.C. Feb 21 '15 at 03:32
  • What is your compilation command? Have you tried using different threading libraries? – diegoperini Feb 28 '15 at 16:49
  • @diegoperini I added the compilation command to the question. What other threading library can I use? std::async is from the C++11 standard - so you mean I can change the underlying implementation that is used? – SebastianK Mar 01 '15 at 21:22
  • 1
    Works fine at MinGW aka `gcc version 4.8.0 (rev2, Built by MinGW-builds project)` – borisbn Mar 02 '15 at 09:19
  • @borisbn Thanks a lot for trying this platform. Did you try it multiple times, since it does not appear in every run (problem appears on about every fifth run)? – SebastianK Mar 02 '15 at 09:24
  • @SebastianK I tried to run your program 15 times - no crashes. I even wrapped the body of `main` in for-cycle from `0` to `1000` - the same result - no crushes – borisbn Mar 02 '15 at 13:59
  • @borisbn Thank you for verifying this – SebastianK Mar 02 '15 at 14:09
  • I reported it as a bug: https://sourceforge.net/p/mingw-w64/bugs/461/ – SebastianK Mar 02 '15 at 21:30
  • FYI @SebastianK Works fine using Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn) Target: x86_64-apple-darwin12.6.0 Thread model: posix – Ben Crowhurst Mar 13 '15 at 11:32
  • My money is on a race condition when the future is moved while it's "member" future is being "satisfied" – Mooing Duck Mar 20 '15 at 22:40
  • What happens if you reduce the number to 5 or something? Starting 200 threads could be an issue. Does the issue still happen if you wait for all before return 0 in main? – Makubex Mar 23 '15 at 12:30
  • @Makubex Yes, I tried the wait before return 0. This does not change anything. But anyway, I assume the waits to happen implicitly, so there is no need for doing them explicitly. In case the number of threads is too large, I would expect a std::system_error Exception. – SebastianK Mar 23 '15 at 12:48
  • it works fine on vs-2013... – Kasim Rangwala Apr 02 '15 at 14:52
  • Spawning 200 threads on Windows is typically not an issue, because Windows imposes only limitation only by system resources, not something like RLIMIT_NPROC in Linux, and typically you would have enough resources for 200 threads, unless you have really bad PC or very resource-limited VM... But to use threads you need to compile with -pthread. So really it looks like a bug in MinGW c++ runtime. Have you tried to link with the debuggable version of runtime and attempt to run under debugger? – ivan.ukr Apr 08 '15 at 04:34
  • @HosseinNarimaniRad Changing the error message in the question to something other than what the runtime will actually report? That's not a good idea, at all. –  Apr 22 '15 at 17:53
  • @hvd Are you sure your comment is related to this question? – SebastianK Apr 22 '15 at 20:02
  • @SebastianK Yes, see the edit history. Hossein Narimani Rad made a bogus edit on your question, and I reverted it to your version. –  Apr 22 '15 at 20:03
  • @hvd Thank you, I didn't consider you were referring to the edit history – SebastianK Apr 22 '15 at 20:07
  • The second error seems interesting. It appears that somehow the program might be trying to put into the same promise twice, which should be a huge no-no. – CinchBlue Apr 25 '15 at 21:12
  • Related: http://stackoverflow.com/questions/3930700/stdfuture-exception-on-gcc-experimental-implementation-of-c0x It seems to have the same error as yours, and the answer was that the guy didn't include pthread either. – CinchBlue Apr 25 '15 at 21:24
  • Can you try updating the compiler to GCC 4.9 or 5.1? Maybe you should try an example with std::promise, as that seems to be the problem here. – CinchBlue Apr 25 '15 at 21:27

1 Answers1

2

Since this answer is still "unanswered," after talking with some people from Lounge<C++>, I think I can say that it's pretty obvious from the comments that this is due to an implementation error either on MinGW/MinGW-w64's or pthread's part at the time. Using gcc 4.9.1, MinGW-W64, the problem does not appear anymore. In fact, the program above appears to compile and run correctly even on a version earlier than 4.8.2 with POSIX threading.

I myself am not an expert, my guess is that the exact trip-up happens when the program appears to try to write to the same promise twice, which, I think, should be a big no-no, as an std::async should write its result only once (again, I'm not sure if I'm right here, and other comments and edits will most likely clarify).

Also, this may be a related problem: std::future exception on gcc experimental implementation of C++0x

Community
  • 1
  • 1
CinchBlue
  • 6,046
  • 1
  • 27
  • 58
  • This bug report thread might be related for pthread: https://sourceware.org/bugzilla/show_bug.cgi?id=12683 – CinchBlue Apr 25 '15 at 22:07
  • 1
    Thank you, I can confirm that the crash disappears with gcc 4.9.1, MinGW-W64 (which was not available within a compiled Windows Qt distribution (the environment for my actual project) at the time I was asking the question) – SebastianK Apr 26 '15 at 10:55
  • It appears to be present in NetBSD 7.0 with GCC 4.8.4, too. Also see [NetBSD 7.0 amd64 and crash in DSA_Signature_Operation::raw_sign](https://github.com/randombit/botan/issues/819). – jww Jan 07 '17 at 03:27