I know we can't call std::future::get
many times, and we should use std::shared_future
if we need to call it many times.
But we can call boost::unique_future::get
many times, although there's boost::shared_future
!
void test1()
{
int i, j;
std::future<int> fu1 = std::async([]{ return 42; });
i = fu1.get();
//j = fu1.get(); // error occur
std::cout << i << std::endl;
boost::unique_future<int> fu2 = boost::async([]{ return 43; });
i = fu2.get();
j = fu2.get(); // sucess...?
std::cout << i << ' ' << j << std::endl;
std::cin.get();
}
The output is:
42
43 43
I thought for a moment and then try this test code.
class TestCls
{
public:
TestCls()
{
std::cout << "[TestCls] default constructor" << std::endl;
}
TestCls(const TestCls &other)
{
std::cout << "[TestCls] copy constructor" << std::endl;
}
TestCls(TestCls &&other)
{
std::cout << "[TestCls] move constructor" << std::endl;
}
TestCls &operator =(const TestCls &other)
{
std::cout << "[TestCls] copy assignment" << std::endl;
return *this;
}
TestCls &operator =(TestCls &&other)
{
std::cout << "[TestCls] move assignment" << std::endl;
return *this;
}
};
void test2()
{
TestCls a, b;
std::cout << std::endl << "unique_future test begin" << std::endl;
boost::unique_future<TestCls> fu1 = boost::async([]{ return TestCls(); });
fu1.wait();
std::cout << "first assignment" << std::endl;
a = fu1.get();
std::cout << "second assignment" << std::endl;
b = fu1.get();
std::cout << "unique_future test end" << std::endl;
std::cout << std::endl << "shared_future test begin" << std::endl;
boost::shared_future<TestCls> fu2 = boost::async([]{ return TestCls(); });
fu2.wait();
std::cout << "first assignment" << std::endl;
a = fu2.get();
std::cout << "second assignment" << std::endl;
b = fu2.get();
std::cout << "shared_future test end" << std::endl;
std::cin.get();
}
The output is:
[TestCls] default constructor
[TestCls] default constructor
unique_future test begin
[TestCls] default constructor
[TestCls] move constructor
first assignment
[TestCls] move constructor
[TestCls] move assignment
second assignment
[TestCls] move constructor
[TestCls] move assignment
unique_future test end
shared_future test begin
[TestCls] default constructor
[TestCls] move constructor
first assignment
[TestCls] copy assignment
second assignment
[TestCls] copy assignment
shared_future test end
Although boost::unique_future
do "move", not "copy", it is allowed to call get
many times.. How is it possible?
(My boost version is 1.55.0, and my compiler is VC++ 2013)
If I do #define BOOST_THREAD_VERSION 4
, an exception occurs at the second call of get()
. multiple call of get()
is undefined behavior until version 3? Or it's allowed until version 3?
From the documentation it's clear that there are at least 3 macro that are playing a significant role in what you are using
which sets the version of the library, even if there are breaking changes between 4 and 3, you don't seem to have a problem with that.
second macro is
BOOST_THREAD_PROVIDES_FUTURE
, this macro is a switch, no value attached, if defined it enables the "standard" futures, not the unique_futures, what you are callingunique_future
is just a placeholder for something that is defined by this macro at compile time.from the file
boost/thread/future.hpp
in the file
boost/thread/detail/config.hpp
you also haveBOOST_THREAD_DONT_PROVIDE_FUTURE
which is another switch for default actionsnote the negation
!
, which means that if you defineBOOST_THREAD_DONT_PROVIDE_FUTURE
you should get "real"unique_future
as documented by the library.You are basically getting the default behaviour and the fact that you are using the version 4 of the library doesn't matter that much.
A side note about C++11 and beyond:
this is bad practice in C++11 and it's undefined behaviour in C++14, you should always specify a launch policy for your
async
.