3

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??

Community
  • 1
  • 1
Wu Fuheng
  • 317
  • 1
  • 3
  • 9
  • 2
    Sounds like a bug in the Linux compiler, but the fact that you say "doesn't exit until the sleep 1000 seconds in Func1 is over" when your code has `sleep(1000 * 1000)` (just over 11 days) makes me think something else is going on. – Ross Ridge Jun 07 '15 at 21:26
  • In C++11 instead of just `sleep` use `std::this_thread::sleep_for` – user2622016 Jun 07 '15 at 22:33
  • Be aware that while on Windows `sleep` takes milliseconds as an argument, on linux it takes seconds. So waiting time of this code is expected to be 1000 times longer on linux. – Ilya Popov Jun 07 '15 at 23:20
  • that's why you should use standard `std::this_thread::sleep_for` - because just `sleep` is not standarized between platforms, and some take seconds, some take miliseconds – user2622016 Jun 08 '15 at 13:14
  • To avoid distraction, please think the snippet as pseudo. In my code, I used a function called mySleep which is an inline of sleep_for but I used sleep here for simplicity as it does not change the nature of the question I was asking. I also did not include header files. Thanks. – Wu Fuheng Jun 08 '15 at 17:22

2 Answers2

3

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?

Community
  • 1
  • 1
Ilya Popov
  • 3,765
  • 1
  • 17
  • 30
-1

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

Community
  • 1
  • 1
user2622016
  • 6,060
  • 3
  • 32
  • 53
  • If the launch::async policy is explicitly specified, the task is actually guaranteed to be executed "as if in a new thread", making this answer wrong. See §30.6.8/3 (N3376). The thread ID may be the same as in a previous async() that has finished, but that doesn't prove anything because the standard only promises the ID of a new thread to be unique among *existing* threads in the first place, not threads that have previously existed (§30.3.2/1 in N3376). – Arne Vogel Jun 08 '15 at 09:21
  • right, and the real cause is the blocking `future` destructor just before catch block – user2622016 Jun 08 '15 at 12:50