0
#include <iostream>
#include <functional>
#include <future>
#include <tchar.h>

void StartBackground(std::function<void()> notify)
{
    auto background = std::async([&]
    {
        notify(); // (A)
    });
}

int _tmain(int argc, _TCHAR* argv[])
{
    StartBackground([](){});

    char c; std::cin >> c;  // (B)
    while (1);
    return 0;
}

1) Build and run the code above using Visual Studio 2012.

2) Line (A) triggers an Access Violation in _VARIADIC_EXPAND_P1_0(_CLASS_FUNC_CLASS_0, , , , ):

First-chance exception at 0x0F96271E (msvcp110d.dll) in ConsoleApplication1.exe: 0xC0000005: Access violation writing location 0x0F9626D8

Most confusingly, the exception can be avoided by removing line (B).

Questions

  • Why does the callable object notify apparently conflict with the use of std::cin?
  • What's wrong with this code?

The real world scenario for this simplified example is a function that executes some code in parallel and have that code call a user-supplied notify function when done.

Edit

I found at least one problem im my code: The background variable is destroyed as soon as StartBackground() exits. Since std::async may or may not start a separate thread, and std::thread calls terminate() if the thread is still joinable, this might be causing the problem. The following variant works because it gives the task enough time to complete:

void StartBackground(std::function<void()> notify)
{
    auto background = std::async([&]
    {
        notify(); // (A)
    });

    std::this_thread::sleep_for(std::chrono::seconds(1));
}

Keeping the std::future object alive over a longer period instead of sleeping should also work. But the following code also causes the same access violation:

std::future<void> background;

void StartBackground(std::function<void()> notify)
{
    background = std::async([&]
    {
        notify(); // (A)
    });
}

whereas using a std::thread in the same manner works as expected:

std::thread background;

void StartBackground(std::function<void()> notify)
{
    background = std::thread([&]
    {
        notify(); // (A)
    });
}

I'm completely puzzled. I must be missing some very crucial points here regarding std::async and std::thread.

1 Answers1

1

The result of async is a future, not a running thread. You have to synchronize on the task by saying background.get(). Without that, the client procedure may never get executed.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Thanks for your hint. It's all about life times. Here, not only `background` went out of scope but the `notify` function was an rvalue passed into `StartBackground()`, too. To rectify my example above, both - the `std::future` and the `std::function` objects - should be lvalues and passed as references. (The forum Software does not allow me to post a more verbose answer yet). – Dr. Frank Heimes May 28 '13 at 10:10
  • @Dr.FrankHeimes: Yeah, lifetime is an issue, too, though the initial code you posted didn't exhibit that. I was in a rush and didn't want to go deeper at the point, but I'll take a look at your edited post. In the meantime, maybe [this post of mine](http://stackoverflow.com/a/12335206/596781) might be of interest. – Kerrek SB May 28 '13 at 11:17