std::async
seems to block even with std::launch::async
flag:
#include <iostream>
#include <future>
#include <chrono>
int main(void)
{
using namespace std::chrono_literals;
auto f = [](const char* s)
{
std::cout << s;
std::this_thread::sleep_for(2s);
std::cout << s;
};
std::cout << "start\n";
(void)std::async(std::launch::async, f, "1\n");
std::cout << "in between\n";
(void)std::async(std::launch::async, f, "2\n");
std::cout << "end\n";
return 0;
}
output shows that the execution is serialized. Even with std::launch::async
flag.
start
1
1
in between
2
2
end
But if I use returned std::future
, it suddenly starts to not block!
The only change I made is removing (void)
and adding auto r1 =
instead:
#include <iostream>
#include <future>
#include <chrono>
int main(void)
{
using namespace std::chrono_literals;
auto f = [](const char* s)
{
std::cout << s;
std::this_thread::sleep_for(2s);
std::cout << s;
};
std::cout << "start\n";
auto r1 = std::async(std::launch::async, f, "1\n");
std::cout << "in between\n";
auto r2 = std::async(std::launch::async, f, "2\n");
std::cout << "end\n";
return 0;
}
And, the result is quite different. It definitely shows that the execution is in parallel.
start
in between
1
end
2
1
2
I used gcc for CentOS devtoolset-7.
gcc (GCC) 7.2.1 20170829 (Red Hat 7.2.1-1)
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
My Makefile
is:
.PHONY: all clean
all: foo
SRCS := $(shell find . -name '*.cpp')
OBJS := $(SRCS:.cpp=.o)
foo: $(OBJS)
gcc -o $@ $^ -lstdc++ -pthread
%.o: %.cpp
gcc -std=c++17 -c -g -Wall -O0 -pthread -o $@ $<
clean:
rm -rf foo *.o
Is this behaviour in the specification?
Or is it a gcc implementation bug?
Why does this happen?
Can someone explain this to me, please?
The std::future
destructor will block if it’s a future from std::async
and is the last reference to the shared state. I believe what you’re seeing here is
async
returns a future
, butfuture
is not being captured, sofuture
fires, whichExplicitly capturing the return value causes the two destructors to fire only at the end of the function, which leaves both tasks running until they’re done.