Different behavior of async with Visual Studio 2013(Windows8.1) and GCC 4.9(Ubuntu14.10)

408 views Asked by At

async has different behavior(implementation) in Windows VS and Linux g++.

I tested it with the following code:

void Func1(){sleep(1000*1000);}
void Func2(){sleep(1000*2);throw runtime_error("An expected exception");}


int main(int argc, char* argv[]){
  try{
    auto f1 = async(launch::async, Func1);
    auto f2 = async(launch::async, Func2);

    f2.get();//block here
    f1.get();
  }catch (exception& e){
    printf("exception: %s\n", e.what());
  }
  return 0;
}

Func1 sleeps for a long time after launch.

Func2 is to throw an exception.

My observation is:

In Windows, the exception is propagated immediately and the main thread(program) will catch it exit accordingly.

In Linux, the exception is held on and the program doesn't exit until the sleep 1000 seconds in Func1 is over.

So does anybody know in Linux, how to make the program catch the exception immediately and exit the program??

2

There are 2 answers

0
Ilya Popov On BEST ANSWER

The future, obtained from async, has a blocking destructor. This "feature" is very controversial and has been discussed many times in the standard committee. See for example this SO question: Why is the destructor of a future returned from `std::async` blocking? The reasoning for such a behaviour is that there is no good portable way to terminate a thread.

Then f2 throws an exception, the f1's destructor is called, which waits until the tread (and thus Func1) finishes. Thus the catch block is executed only after the Func1 finishes.

As of Windows behaviour, this is a known VC++ bug, as discussed here: std::list<std::future> destructor does not block

So, GCC on Linux is right, and VC++ on Windows is wrong here.

For a workaround, see for example Workaround for blocking async?

2
user2622016 On

Try comparing in Func1 and Func2 result of:

std::cout << std::this_thread::get_id() << std::endl;

async is not guaranteed by the standard to be executed in separate thread.

Probably you could use std::packaged_task with std::thread, like in the example:

std::packaged_task< int(int) > package{ Func2 };
std::future<void> f2 = package.get_future();
std::thread t { std::move(package) };

f2.get();       //block here until t finishes

t.join();

See my answer regarding std::packaged_task on https://stackoverflow.com/a/24164631/2622016