| // (C) Copyright 2008-10 Anthony Williams |
| // |
| // Distributed under the Boost Software License, Version 1.0. (See |
| // accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| |
| #include "boost/thread/thread.hpp" |
| #include "boost/thread/mutex.hpp" |
| #include "boost/thread/condition.hpp" |
| #include "boost/thread/future.hpp" |
| #include <utility> |
| #include <memory> |
| #include <string> |
| |
| #include <boost/test/unit_test.hpp> |
| |
| #ifndef BOOST_NO_RVALUE_REFERENCES |
| template<typename T> |
| typename boost::remove_reference<T>::type&& cast_to_rval(T&& t) |
| { |
| return static_cast<typename boost::remove_reference<T>::type&&>(t); |
| } |
| #else |
| template<typename T> |
| boost::detail::thread_move_t<T> cast_to_rval(T& t) |
| { |
| return boost::move(t); |
| } |
| #endif |
| |
| struct X |
| { |
| private: |
| |
| X(X& other); |
| |
| public: |
| |
| int i; |
| |
| X(): |
| i(42) |
| {} |
| #ifndef BOOST_NO_RVALUE_REFERENCES |
| X(X&& other): |
| i(other.i) |
| { |
| other.i=0; |
| } |
| #else |
| X(boost::detail::thread_move_t<X> other): |
| i(other->i) |
| { |
| other->i=0; |
| } |
| operator boost::detail::thread_move_t<X>() |
| { |
| return boost::detail::thread_move_t<X>(*this); |
| } |
| #endif |
| ~X() |
| {} |
| }; |
| |
| int make_int() |
| { |
| return 42; |
| } |
| |
| int throw_runtime_error() |
| { |
| throw std::runtime_error("42"); |
| } |
| |
| void set_promise_thread(boost::promise<int>* p) |
| { |
| p->set_value(42); |
| } |
| |
| struct my_exception |
| {}; |
| |
| void set_promise_exception_thread(boost::promise<int>* p) |
| { |
| p->set_exception(boost::copy_exception(my_exception())); |
| } |
| |
| |
| void test_store_value_from_thread() |
| { |
| boost::promise<int> pi2; |
| boost::unique_future<int> fi2(pi2.get_future()); |
| boost::thread(set_promise_thread,&pi2); |
| int j=fi2.get(); |
| BOOST_CHECK(j==42); |
| BOOST_CHECK(fi2.is_ready()); |
| BOOST_CHECK(fi2.has_value()); |
| BOOST_CHECK(!fi2.has_exception()); |
| BOOST_CHECK(fi2.get_state()==boost::future_state::ready); |
| } |
| |
| |
| void test_store_exception() |
| { |
| boost::promise<int> pi3; |
| boost::unique_future<int> fi3=pi3.get_future(); |
| boost::thread(set_promise_exception_thread,&pi3); |
| try |
| { |
| fi3.get(); |
| BOOST_CHECK(false); |
| } |
| catch(my_exception) |
| { |
| BOOST_CHECK(true); |
| } |
| |
| BOOST_CHECK(fi3.is_ready()); |
| BOOST_CHECK(!fi3.has_value()); |
| BOOST_CHECK(fi3.has_exception()); |
| BOOST_CHECK(fi3.get_state()==boost::future_state::ready); |
| } |
| |
| void test_initial_state() |
| { |
| boost::unique_future<int> fi; |
| BOOST_CHECK(!fi.is_ready()); |
| BOOST_CHECK(!fi.has_value()); |
| BOOST_CHECK(!fi.has_exception()); |
| BOOST_CHECK(fi.get_state()==boost::future_state::uninitialized); |
| int i; |
| try |
| { |
| i=fi.get(); |
| BOOST_CHECK(false); |
| } |
| catch(boost::future_uninitialized) |
| { |
| BOOST_CHECK(true); |
| } |
| } |
| |
| void test_waiting_future() |
| { |
| boost::promise<int> pi; |
| boost::unique_future<int> fi; |
| fi=pi.get_future(); |
| |
| int i=0; |
| BOOST_CHECK(!fi.is_ready()); |
| BOOST_CHECK(!fi.has_value()); |
| BOOST_CHECK(!fi.has_exception()); |
| BOOST_CHECK(fi.get_state()==boost::future_state::waiting); |
| BOOST_CHECK(i==0); |
| } |
| |
| void test_cannot_get_future_twice() |
| { |
| boost::promise<int> pi; |
| pi.get_future(); |
| |
| try |
| { |
| pi.get_future(); |
| BOOST_CHECK(false); |
| } |
| catch(boost::future_already_retrieved&) |
| { |
| BOOST_CHECK(true); |
| } |
| } |
| |
| void test_set_value_updates_future_state() |
| { |
| boost::promise<int> pi; |
| boost::unique_future<int> fi; |
| fi=pi.get_future(); |
| |
| pi.set_value(42); |
| |
| BOOST_CHECK(fi.is_ready()); |
| BOOST_CHECK(fi.has_value()); |
| BOOST_CHECK(!fi.has_exception()); |
| BOOST_CHECK(fi.get_state()==boost::future_state::ready); |
| } |
| |
| void test_set_value_can_be_retrieved() |
| { |
| boost::promise<int> pi; |
| boost::unique_future<int> fi; |
| fi=pi.get_future(); |
| |
| pi.set_value(42); |
| |
| int i=0; |
| BOOST_CHECK(i=fi.get()); |
| BOOST_CHECK(i==42); |
| BOOST_CHECK(fi.is_ready()); |
| BOOST_CHECK(fi.has_value()); |
| BOOST_CHECK(!fi.has_exception()); |
| BOOST_CHECK(fi.get_state()==boost::future_state::ready); |
| } |
| |
| void test_set_value_can_be_moved() |
| { |
| // boost::promise<int> pi; |
| // boost::unique_future<int> fi; |
| // fi=pi.get_future(); |
| |
| // pi.set_value(42); |
| |
| // int i=0; |
| // BOOST_CHECK(i=fi.get()); |
| // BOOST_CHECK(i==42); |
| // BOOST_CHECK(fi.is_ready()); |
| // BOOST_CHECK(fi.has_value()); |
| // BOOST_CHECK(!fi.has_exception()); |
| // BOOST_CHECK(fi.get_state()==boost::future_state::ready); |
| } |
| |
| void test_future_from_packaged_task_is_waiting() |
| { |
| boost::packaged_task<int> pt(make_int); |
| boost::unique_future<int> fi=pt.get_future(); |
| int i=0; |
| BOOST_CHECK(!fi.is_ready()); |
| BOOST_CHECK(!fi.has_value()); |
| BOOST_CHECK(!fi.has_exception()); |
| BOOST_CHECK(fi.get_state()==boost::future_state::waiting); |
| BOOST_CHECK(i==0); |
| } |
| |
| void test_invoking_a_packaged_task_populates_future() |
| { |
| boost::packaged_task<int> pt(make_int); |
| boost::unique_future<int> fi=pt.get_future(); |
| |
| pt(); |
| |
| int i=0; |
| BOOST_CHECK(fi.is_ready()); |
| BOOST_CHECK(fi.has_value()); |
| BOOST_CHECK(!fi.has_exception()); |
| BOOST_CHECK(fi.get_state()==boost::future_state::ready); |
| BOOST_CHECK(i=fi.get()); |
| BOOST_CHECK(i==42); |
| } |
| |
| void test_invoking_a_packaged_task_twice_throws() |
| { |
| boost::packaged_task<int> pt(make_int); |
| |
| pt(); |
| try |
| { |
| pt(); |
| BOOST_CHECK(false); |
| } |
| catch(boost::task_already_started) |
| { |
| BOOST_CHECK(true); |
| } |
| } |
| |
| |
| void test_cannot_get_future_twice_from_task() |
| { |
| boost::packaged_task<int> pt(make_int); |
| pt.get_future(); |
| try |
| { |
| pt.get_future(); |
| BOOST_CHECK(false); |
| } |
| catch(boost::future_already_retrieved) |
| { |
| BOOST_CHECK(true); |
| } |
| } |
| |
| void test_task_stores_exception_if_function_throws() |
| { |
| boost::packaged_task<int> pt(throw_runtime_error); |
| boost::unique_future<int> fi=pt.get_future(); |
| |
| pt(); |
| |
| BOOST_CHECK(fi.is_ready()); |
| BOOST_CHECK(!fi.has_value()); |
| BOOST_CHECK(fi.has_exception()); |
| BOOST_CHECK(fi.get_state()==boost::future_state::ready); |
| try |
| { |
| fi.get(); |
| BOOST_CHECK(false); |
| } |
| catch(std::exception&) |
| { |
| BOOST_CHECK(true); |
| } |
| catch(...) |
| { |
| BOOST_CHECK(!"Unknown exception thrown"); |
| } |
| |
| } |
| |
| void test_void_promise() |
| { |
| boost::promise<void> p; |
| boost::unique_future<void> f=p.get_future(); |
| p.set_value(); |
| BOOST_CHECK(f.is_ready()); |
| BOOST_CHECK(f.has_value()); |
| BOOST_CHECK(!f.has_exception()); |
| BOOST_CHECK(f.get_state()==boost::future_state::ready); |
| f.get(); |
| } |
| |
| void test_reference_promise() |
| { |
| boost::promise<int&> p; |
| boost::unique_future<int&> f=p.get_future(); |
| int i=42; |
| p.set_value(i); |
| BOOST_CHECK(f.is_ready()); |
| BOOST_CHECK(f.has_value()); |
| BOOST_CHECK(!f.has_exception()); |
| BOOST_CHECK(f.get_state()==boost::future_state::ready); |
| BOOST_CHECK(&f.get()==&i); |
| } |
| |
| void do_nothing() |
| {} |
| |
| void test_task_returning_void() |
| { |
| boost::packaged_task<void> pt(do_nothing); |
| boost::unique_future<void> fi=pt.get_future(); |
| |
| pt(); |
| |
| BOOST_CHECK(fi.is_ready()); |
| BOOST_CHECK(fi.has_value()); |
| BOOST_CHECK(!fi.has_exception()); |
| BOOST_CHECK(fi.get_state()==boost::future_state::ready); |
| } |
| |
| int global_ref_target=0; |
| |
| int& return_ref() |
| { |
| return global_ref_target; |
| } |
| |
| void test_task_returning_reference() |
| { |
| boost::packaged_task<int&> pt(return_ref); |
| boost::unique_future<int&> fi=pt.get_future(); |
| |
| pt(); |
| |
| BOOST_CHECK(fi.is_ready()); |
| BOOST_CHECK(fi.has_value()); |
| BOOST_CHECK(!fi.has_exception()); |
| BOOST_CHECK(fi.get_state()==boost::future_state::ready); |
| int& i=fi.get(); |
| BOOST_CHECK(&i==&global_ref_target); |
| } |
| |
| void test_shared_future() |
| { |
| boost::packaged_task<int> pt(make_int); |
| boost::unique_future<int> fi=pt.get_future(); |
| |
| boost::shared_future<int> sf(::cast_to_rval(fi)); |
| BOOST_CHECK(fi.get_state()==boost::future_state::uninitialized); |
| |
| pt(); |
| |
| int i=0; |
| BOOST_CHECK(sf.is_ready()); |
| BOOST_CHECK(sf.has_value()); |
| BOOST_CHECK(!sf.has_exception()); |
| BOOST_CHECK(sf.get_state()==boost::future_state::ready); |
| BOOST_CHECK(i=sf.get()); |
| BOOST_CHECK(i==42); |
| } |
| |
| void test_copies_of_shared_future_become_ready_together() |
| { |
| boost::packaged_task<int> pt(make_int); |
| boost::unique_future<int> fi=pt.get_future(); |
| |
| boost::shared_future<int> sf(::cast_to_rval(fi)); |
| boost::shared_future<int> sf2(sf); |
| boost::shared_future<int> sf3; |
| sf3=sf; |
| BOOST_CHECK(sf.get_state()==boost::future_state::waiting); |
| BOOST_CHECK(sf2.get_state()==boost::future_state::waiting); |
| BOOST_CHECK(sf3.get_state()==boost::future_state::waiting); |
| |
| pt(); |
| |
| int i=0; |
| BOOST_CHECK(sf.is_ready()); |
| BOOST_CHECK(sf.has_value()); |
| BOOST_CHECK(!sf.has_exception()); |
| BOOST_CHECK(sf.get_state()==boost::future_state::ready); |
| BOOST_CHECK(i=sf.get()); |
| BOOST_CHECK(i==42); |
| i=0; |
| BOOST_CHECK(sf2.is_ready()); |
| BOOST_CHECK(sf2.has_value()); |
| BOOST_CHECK(!sf2.has_exception()); |
| BOOST_CHECK(sf2.get_state()==boost::future_state::ready); |
| BOOST_CHECK(i=sf2.get()); |
| BOOST_CHECK(i==42); |
| i=0; |
| BOOST_CHECK(sf3.is_ready()); |
| BOOST_CHECK(sf3.has_value()); |
| BOOST_CHECK(!sf3.has_exception()); |
| BOOST_CHECK(sf3.get_state()==boost::future_state::ready); |
| BOOST_CHECK(i=sf3.get()); |
| BOOST_CHECK(i==42); |
| } |
| |
| void test_shared_future_can_be_move_assigned_from_unique_future() |
| { |
| boost::packaged_task<int> pt(make_int); |
| boost::unique_future<int> fi=pt.get_future(); |
| |
| boost::shared_future<int> sf; |
| sf=::cast_to_rval(fi); |
| BOOST_CHECK(fi.get_state()==boost::future_state::uninitialized); |
| |
| BOOST_CHECK(!sf.is_ready()); |
| BOOST_CHECK(!sf.has_value()); |
| BOOST_CHECK(!sf.has_exception()); |
| BOOST_CHECK(sf.get_state()==boost::future_state::waiting); |
| } |
| |
| void test_shared_future_void() |
| { |
| boost::packaged_task<void> pt(do_nothing); |
| boost::unique_future<void> fi=pt.get_future(); |
| |
| boost::shared_future<void> sf(::cast_to_rval(fi)); |
| BOOST_CHECK(fi.get_state()==boost::future_state::uninitialized); |
| |
| pt(); |
| |
| BOOST_CHECK(sf.is_ready()); |
| BOOST_CHECK(sf.has_value()); |
| BOOST_CHECK(!sf.has_exception()); |
| BOOST_CHECK(sf.get_state()==boost::future_state::ready); |
| sf.get(); |
| } |
| |
| void test_shared_future_ref() |
| { |
| boost::promise<int&> p; |
| boost::shared_future<int&> f(p.get_future()); |
| int i=42; |
| p.set_value(i); |
| BOOST_CHECK(f.is_ready()); |
| BOOST_CHECK(f.has_value()); |
| BOOST_CHECK(!f.has_exception()); |
| BOOST_CHECK(f.get_state()==boost::future_state::ready); |
| BOOST_CHECK(&f.get()==&i); |
| } |
| |
| void test_can_get_a_second_future_from_a_moved_promise() |
| { |
| boost::promise<int> pi; |
| boost::unique_future<int> fi=pi.get_future(); |
| |
| boost::promise<int> pi2(::cast_to_rval(pi)); |
| boost::unique_future<int> fi2=pi.get_future(); |
| |
| pi2.set_value(3); |
| BOOST_CHECK(fi.is_ready()); |
| BOOST_CHECK(!fi2.is_ready()); |
| BOOST_CHECK(fi.get()==3); |
| pi.set_value(42); |
| BOOST_CHECK(fi2.is_ready()); |
| BOOST_CHECK(fi2.get()==42); |
| } |
| |
| void test_can_get_a_second_future_from_a_moved_void_promise() |
| { |
| boost::promise<void> pi; |
| boost::unique_future<void> fi=pi.get_future(); |
| |
| boost::promise<void> pi2(::cast_to_rval(pi)); |
| boost::unique_future<void> fi2=pi.get_future(); |
| |
| pi2.set_value(); |
| BOOST_CHECK(fi.is_ready()); |
| BOOST_CHECK(!fi2.is_ready()); |
| pi.set_value(); |
| BOOST_CHECK(fi2.is_ready()); |
| } |
| |
| void test_unique_future_for_move_only_udt() |
| { |
| boost::promise<X> pt; |
| boost::unique_future<X> fi=pt.get_future(); |
| |
| pt.set_value(X()); |
| X res(fi.get()); |
| BOOST_CHECK(res.i==42); |
| } |
| |
| void test_unique_future_for_string() |
| { |
| boost::promise<std::string> pt; |
| boost::unique_future<std::string> fi=pt.get_future(); |
| |
| pt.set_value(std::string("hello")); |
| std::string res(fi.get()); |
| BOOST_CHECK(res=="hello"); |
| |
| boost::promise<std::string> pt2; |
| fi=pt2.get_future(); |
| |
| std::string const s="goodbye"; |
| |
| pt2.set_value(s); |
| res=fi.get(); |
| BOOST_CHECK(res=="goodbye"); |
| |
| boost::promise<std::string> pt3; |
| fi=pt3.get_future(); |
| |
| std::string s2="foo"; |
| |
| pt3.set_value(s2); |
| res=fi.get(); |
| BOOST_CHECK(res=="foo"); |
| } |
| |
| boost::mutex callback_mutex; |
| unsigned callback_called=0; |
| |
| void wait_callback(boost::promise<int>& pi) |
| { |
| boost::lock_guard<boost::mutex> lk(callback_mutex); |
| ++callback_called; |
| try |
| { |
| pi.set_value(42); |
| } |
| catch(...) |
| { |
| } |
| } |
| |
| void do_nothing_callback(boost::promise<int>& /*pi*/) |
| { |
| boost::lock_guard<boost::mutex> lk(callback_mutex); |
| ++callback_called; |
| } |
| |
| void test_wait_callback() |
| { |
| callback_called=0; |
| boost::promise<int> pi; |
| boost::unique_future<int> fi=pi.get_future(); |
| pi.set_wait_callback(wait_callback); |
| fi.wait(); |
| BOOST_CHECK(callback_called); |
| BOOST_CHECK(fi.get()==42); |
| fi.wait(); |
| fi.wait(); |
| BOOST_CHECK(callback_called==1); |
| } |
| |
| void test_wait_callback_with_timed_wait() |
| { |
| callback_called=0; |
| boost::promise<int> pi; |
| boost::unique_future<int> fi=pi.get_future(); |
| pi.set_wait_callback(do_nothing_callback); |
| bool success=fi.timed_wait(boost::posix_time::milliseconds(10)); |
| BOOST_CHECK(callback_called); |
| BOOST_CHECK(!success); |
| success=fi.timed_wait(boost::posix_time::milliseconds(10)); |
| BOOST_CHECK(!success); |
| success=fi.timed_wait(boost::posix_time::milliseconds(10)); |
| BOOST_CHECK(!success); |
| BOOST_CHECK(callback_called==3); |
| pi.set_value(42); |
| success=fi.timed_wait(boost::posix_time::milliseconds(10)); |
| BOOST_CHECK(success); |
| BOOST_CHECK(callback_called==3); |
| BOOST_CHECK(fi.get()==42); |
| BOOST_CHECK(callback_called==3); |
| } |
| |
| |
| void wait_callback_for_task(boost::packaged_task<int>& pt) |
| { |
| boost::lock_guard<boost::mutex> lk(callback_mutex); |
| ++callback_called; |
| try |
| { |
| pt(); |
| } |
| catch(...) |
| { |
| } |
| } |
| |
| |
| void test_wait_callback_for_packaged_task() |
| { |
| callback_called=0; |
| boost::packaged_task<int> pt(make_int); |
| boost::unique_future<int> fi=pt.get_future(); |
| pt.set_wait_callback(wait_callback_for_task); |
| fi.wait(); |
| BOOST_CHECK(callback_called); |
| BOOST_CHECK(fi.get()==42); |
| fi.wait(); |
| fi.wait(); |
| BOOST_CHECK(callback_called==1); |
| } |
| |
| void test_packaged_task_can_be_moved() |
| { |
| boost::packaged_task<int> pt(make_int); |
| |
| boost::unique_future<int> fi=pt.get_future(); |
| |
| BOOST_CHECK(!fi.is_ready()); |
| |
| boost::packaged_task<int> pt2(::cast_to_rval(pt)); |
| |
| BOOST_CHECK(!fi.is_ready()); |
| try |
| { |
| pt(); |
| BOOST_CHECK(!"Can invoke moved task!"); |
| } |
| catch(boost::task_moved&) |
| { |
| } |
| |
| BOOST_CHECK(!fi.is_ready()); |
| |
| pt2(); |
| |
| BOOST_CHECK(fi.is_ready()); |
| } |
| |
| void test_destroying_a_promise_stores_broken_promise() |
| { |
| boost::unique_future<int> f; |
| |
| { |
| boost::promise<int> p; |
| f=p.get_future(); |
| } |
| BOOST_CHECK(f.is_ready()); |
| BOOST_CHECK(f.has_exception()); |
| try |
| { |
| f.get(); |
| } |
| catch(boost::broken_promise&) |
| { |
| } |
| } |
| |
| void test_destroying_a_packaged_task_stores_broken_promise() |
| { |
| boost::unique_future<int> f; |
| |
| { |
| boost::packaged_task<int> p(make_int); |
| f=p.get_future(); |
| } |
| BOOST_CHECK(f.is_ready()); |
| BOOST_CHECK(f.has_exception()); |
| try |
| { |
| f.get(); |
| } |
| catch(boost::broken_promise&) |
| { |
| } |
| } |
| |
| int make_int_slowly() |
| { |
| boost::this_thread::sleep(boost::posix_time::seconds(1)); |
| return 42; |
| } |
| |
| void test_wait_for_either_of_two_futures_1() |
| { |
| boost::packaged_task<int> pt(make_int_slowly); |
| boost::unique_future<int> f1(pt.get_future()); |
| boost::packaged_task<int> pt2(make_int_slowly); |
| boost::unique_future<int> f2(pt2.get_future()); |
| |
| boost::thread(::cast_to_rval(pt)); |
| |
| unsigned const future=boost::wait_for_any(f1,f2); |
| |
| BOOST_CHECK(future==0); |
| BOOST_CHECK(f1.is_ready()); |
| BOOST_CHECK(!f2.is_ready()); |
| BOOST_CHECK(f1.get()==42); |
| } |
| |
| void test_wait_for_either_of_two_futures_2() |
| { |
| boost::packaged_task<int> pt(make_int_slowly); |
| boost::unique_future<int> f1(pt.get_future()); |
| boost::packaged_task<int> pt2(make_int_slowly); |
| boost::unique_future<int> f2(pt2.get_future()); |
| |
| boost::thread(::cast_to_rval(pt2)); |
| |
| unsigned const future=boost::wait_for_any(f1,f2); |
| |
| BOOST_CHECK(future==1); |
| BOOST_CHECK(!f1.is_ready()); |
| BOOST_CHECK(f2.is_ready()); |
| BOOST_CHECK(f2.get()==42); |
| } |
| |
| void test_wait_for_either_of_three_futures_1() |
| { |
| boost::packaged_task<int> pt(make_int_slowly); |
| boost::unique_future<int> f1(pt.get_future()); |
| boost::packaged_task<int> pt2(make_int_slowly); |
| boost::unique_future<int> f2(pt2.get_future()); |
| boost::packaged_task<int> pt3(make_int_slowly); |
| boost::unique_future<int> f3(pt3.get_future()); |
| |
| boost::thread(::cast_to_rval(pt)); |
| |
| unsigned const future=boost::wait_for_any(f1,f2,f3); |
| |
| BOOST_CHECK(future==0); |
| BOOST_CHECK(f1.is_ready()); |
| BOOST_CHECK(!f2.is_ready()); |
| BOOST_CHECK(!f3.is_ready()); |
| BOOST_CHECK(f1.get()==42); |
| } |
| |
| void test_wait_for_either_of_three_futures_2() |
| { |
| boost::packaged_task<int> pt(make_int_slowly); |
| boost::unique_future<int> f1(pt.get_future()); |
| boost::packaged_task<int> pt2(make_int_slowly); |
| boost::unique_future<int> f2(pt2.get_future()); |
| boost::packaged_task<int> pt3(make_int_slowly); |
| boost::unique_future<int> f3(pt3.get_future()); |
| |
| boost::thread(::cast_to_rval(pt2)); |
| |
| unsigned const future=boost::wait_for_any(f1,f2,f3); |
| |
| BOOST_CHECK(future==1); |
| BOOST_CHECK(!f1.is_ready()); |
| BOOST_CHECK(f2.is_ready()); |
| BOOST_CHECK(!f3.is_ready()); |
| BOOST_CHECK(f2.get()==42); |
| } |
| |
| void test_wait_for_either_of_three_futures_3() |
| { |
| boost::packaged_task<int> pt(make_int_slowly); |
| boost::unique_future<int> f1(pt.get_future()); |
| boost::packaged_task<int> pt2(make_int_slowly); |
| boost::unique_future<int> f2(pt2.get_future()); |
| boost::packaged_task<int> pt3(make_int_slowly); |
| boost::unique_future<int> f3(pt3.get_future()); |
| |
| boost::thread(::cast_to_rval(pt3)); |
| |
| unsigned const future=boost::wait_for_any(f1,f2,f3); |
| |
| BOOST_CHECK(future==2); |
| BOOST_CHECK(!f1.is_ready()); |
| BOOST_CHECK(!f2.is_ready()); |
| BOOST_CHECK(f3.is_ready()); |
| BOOST_CHECK(f3.get()==42); |
| } |
| |
| void test_wait_for_either_of_four_futures_1() |
| { |
| boost::packaged_task<int> pt(make_int_slowly); |
| boost::unique_future<int> f1(pt.get_future()); |
| boost::packaged_task<int> pt2(make_int_slowly); |
| boost::unique_future<int> f2(pt2.get_future()); |
| boost::packaged_task<int> pt3(make_int_slowly); |
| boost::unique_future<int> f3(pt3.get_future()); |
| boost::packaged_task<int> pt4(make_int_slowly); |
| boost::unique_future<int> f4(pt4.get_future()); |
| |
| boost::thread(::cast_to_rval(pt)); |
| |
| unsigned const future=boost::wait_for_any(f1,f2,f3,f4); |
| |
| BOOST_CHECK(future==0); |
| BOOST_CHECK(f1.is_ready()); |
| BOOST_CHECK(!f2.is_ready()); |
| BOOST_CHECK(!f3.is_ready()); |
| BOOST_CHECK(!f4.is_ready()); |
| BOOST_CHECK(f1.get()==42); |
| } |
| |
| void test_wait_for_either_of_four_futures_2() |
| { |
| boost::packaged_task<int> pt(make_int_slowly); |
| boost::unique_future<int> f1(pt.get_future()); |
| boost::packaged_task<int> pt2(make_int_slowly); |
| boost::unique_future<int> f2(pt2.get_future()); |
| boost::packaged_task<int> pt3(make_int_slowly); |
| boost::unique_future<int> f3(pt3.get_future()); |
| boost::packaged_task<int> pt4(make_int_slowly); |
| boost::unique_future<int> f4(pt4.get_future()); |
| |
| boost::thread(::cast_to_rval(pt2)); |
| |
| unsigned const future=boost::wait_for_any(f1,f2,f3,f4); |
| |
| BOOST_CHECK(future==1); |
| BOOST_CHECK(!f1.is_ready()); |
| BOOST_CHECK(f2.is_ready()); |
| BOOST_CHECK(!f3.is_ready()); |
| BOOST_CHECK(!f4.is_ready()); |
| BOOST_CHECK(f2.get()==42); |
| } |
| |
| void test_wait_for_either_of_four_futures_3() |
| { |
| boost::packaged_task<int> pt(make_int_slowly); |
| boost::unique_future<int> f1(pt.get_future()); |
| boost::packaged_task<int> pt2(make_int_slowly); |
| boost::unique_future<int> f2(pt2.get_future()); |
| boost::packaged_task<int> pt3(make_int_slowly); |
| boost::unique_future<int> f3(pt3.get_future()); |
| boost::packaged_task<int> pt4(make_int_slowly); |
| boost::unique_future<int> f4(pt4.get_future()); |
| |
| boost::thread(::cast_to_rval(pt3)); |
| |
| unsigned const future=boost::wait_for_any(f1,f2,f3,f4); |
| |
| BOOST_CHECK(future==2); |
| BOOST_CHECK(!f1.is_ready()); |
| BOOST_CHECK(!f2.is_ready()); |
| BOOST_CHECK(f3.is_ready()); |
| BOOST_CHECK(!f4.is_ready()); |
| BOOST_CHECK(f3.get()==42); |
| } |
| |
| void test_wait_for_either_of_four_futures_4() |
| { |
| boost::packaged_task<int> pt(make_int_slowly); |
| boost::unique_future<int> f1(pt.get_future()); |
| boost::packaged_task<int> pt2(make_int_slowly); |
| boost::unique_future<int> f2(pt2.get_future()); |
| boost::packaged_task<int> pt3(make_int_slowly); |
| boost::unique_future<int> f3(pt3.get_future()); |
| boost::packaged_task<int> pt4(make_int_slowly); |
| boost::unique_future<int> f4(pt4.get_future()); |
| |
| boost::thread(::cast_to_rval(pt4)); |
| |
| unsigned const future=boost::wait_for_any(f1,f2,f3,f4); |
| |
| BOOST_CHECK(future==3); |
| BOOST_CHECK(!f1.is_ready()); |
| BOOST_CHECK(!f2.is_ready()); |
| BOOST_CHECK(!f3.is_ready()); |
| BOOST_CHECK(f4.is_ready()); |
| BOOST_CHECK(f4.get()==42); |
| } |
| |
| void test_wait_for_either_of_five_futures_1() |
| { |
| boost::packaged_task<int> pt(make_int_slowly); |
| boost::unique_future<int> f1(pt.get_future()); |
| boost::packaged_task<int> pt2(make_int_slowly); |
| boost::unique_future<int> f2(pt2.get_future()); |
| boost::packaged_task<int> pt3(make_int_slowly); |
| boost::unique_future<int> f3(pt3.get_future()); |
| boost::packaged_task<int> pt4(make_int_slowly); |
| boost::unique_future<int> f4(pt4.get_future()); |
| boost::packaged_task<int> pt5(make_int_slowly); |
| boost::unique_future<int> f5(pt5.get_future()); |
| |
| boost::thread(::cast_to_rval(pt)); |
| |
| unsigned const future=boost::wait_for_any(f1,f2,f3,f4,f5); |
| |
| BOOST_CHECK(future==0); |
| BOOST_CHECK(f1.is_ready()); |
| BOOST_CHECK(!f2.is_ready()); |
| BOOST_CHECK(!f3.is_ready()); |
| BOOST_CHECK(!f4.is_ready()); |
| BOOST_CHECK(!f5.is_ready()); |
| BOOST_CHECK(f1.get()==42); |
| } |
| |
| void test_wait_for_either_of_five_futures_2() |
| { |
| boost::packaged_task<int> pt(make_int_slowly); |
| boost::unique_future<int> f1(pt.get_future()); |
| boost::packaged_task<int> pt2(make_int_slowly); |
| boost::unique_future<int> f2(pt2.get_future()); |
| boost::packaged_task<int> pt3(make_int_slowly); |
| boost::unique_future<int> f3(pt3.get_future()); |
| boost::packaged_task<int> pt4(make_int_slowly); |
| boost::unique_future<int> f4(pt4.get_future()); |
| boost::packaged_task<int> pt5(make_int_slowly); |
| boost::unique_future<int> f5(pt5.get_future()); |
| |
| boost::thread(::cast_to_rval(pt2)); |
| |
| unsigned const future=boost::wait_for_any(f1,f2,f3,f4,f5); |
| |
| BOOST_CHECK(future==1); |
| BOOST_CHECK(!f1.is_ready()); |
| BOOST_CHECK(f2.is_ready()); |
| BOOST_CHECK(!f3.is_ready()); |
| BOOST_CHECK(!f4.is_ready()); |
| BOOST_CHECK(!f5.is_ready()); |
| BOOST_CHECK(f2.get()==42); |
| } |
| void test_wait_for_either_of_five_futures_3() |
| { |
| boost::packaged_task<int> pt(make_int_slowly); |
| boost::unique_future<int> f1(pt.get_future()); |
| boost::packaged_task<int> pt2(make_int_slowly); |
| boost::unique_future<int> f2(pt2.get_future()); |
| boost::packaged_task<int> pt3(make_int_slowly); |
| boost::unique_future<int> f3(pt3.get_future()); |
| boost::packaged_task<int> pt4(make_int_slowly); |
| boost::unique_future<int> f4(pt4.get_future()); |
| boost::packaged_task<int> pt5(make_int_slowly); |
| boost::unique_future<int> f5(pt5.get_future()); |
| |
| boost::thread(::cast_to_rval(pt3)); |
| |
| unsigned const future=boost::wait_for_any(f1,f2,f3,f4,f5); |
| |
| BOOST_CHECK(future==2); |
| BOOST_CHECK(!f1.is_ready()); |
| BOOST_CHECK(!f2.is_ready()); |
| BOOST_CHECK(f3.is_ready()); |
| BOOST_CHECK(!f4.is_ready()); |
| BOOST_CHECK(!f5.is_ready()); |
| BOOST_CHECK(f3.get()==42); |
| } |
| void test_wait_for_either_of_five_futures_4() |
| { |
| boost::packaged_task<int> pt(make_int_slowly); |
| boost::unique_future<int> f1(pt.get_future()); |
| boost::packaged_task<int> pt2(make_int_slowly); |
| boost::unique_future<int> f2(pt2.get_future()); |
| boost::packaged_task<int> pt3(make_int_slowly); |
| boost::unique_future<int> f3(pt3.get_future()); |
| boost::packaged_task<int> pt4(make_int_slowly); |
| boost::unique_future<int> f4(pt4.get_future()); |
| boost::packaged_task<int> pt5(make_int_slowly); |
| boost::unique_future<int> f5(pt5.get_future()); |
| |
| boost::thread(::cast_to_rval(pt4)); |
| |
| unsigned const future=boost::wait_for_any(f1,f2,f3,f4,f5); |
| |
| BOOST_CHECK(future==3); |
| BOOST_CHECK(!f1.is_ready()); |
| BOOST_CHECK(!f2.is_ready()); |
| BOOST_CHECK(!f3.is_ready()); |
| BOOST_CHECK(f4.is_ready()); |
| BOOST_CHECK(!f5.is_ready()); |
| BOOST_CHECK(f4.get()==42); |
| } |
| void test_wait_for_either_of_five_futures_5() |
| { |
| boost::packaged_task<int> pt(make_int_slowly); |
| boost::unique_future<int> f1(pt.get_future()); |
| boost::packaged_task<int> pt2(make_int_slowly); |
| boost::unique_future<int> f2(pt2.get_future()); |
| boost::packaged_task<int> pt3(make_int_slowly); |
| boost::unique_future<int> f3(pt3.get_future()); |
| boost::packaged_task<int> pt4(make_int_slowly); |
| boost::unique_future<int> f4(pt4.get_future()); |
| boost::packaged_task<int> pt5(make_int_slowly); |
| boost::unique_future<int> f5(pt5.get_future()); |
| |
| boost::thread(::cast_to_rval(pt5)); |
| |
| unsigned const future=boost::wait_for_any(f1,f2,f3,f4,f5); |
| |
| BOOST_CHECK(future==4); |
| BOOST_CHECK(!f1.is_ready()); |
| BOOST_CHECK(!f2.is_ready()); |
| BOOST_CHECK(!f3.is_ready()); |
| BOOST_CHECK(!f4.is_ready()); |
| BOOST_CHECK(f5.is_ready()); |
| BOOST_CHECK(f5.get()==42); |
| } |
| |
| void test_wait_for_either_invokes_callbacks() |
| { |
| callback_called=0; |
| boost::packaged_task<int> pt(make_int_slowly); |
| boost::unique_future<int> fi=pt.get_future(); |
| boost::packaged_task<int> pt2(make_int_slowly); |
| boost::unique_future<int> fi2=pt2.get_future(); |
| pt.set_wait_callback(wait_callback_for_task); |
| |
| boost::thread(::cast_to_rval(pt)); |
| |
| boost::wait_for_any(fi,fi2); |
| BOOST_CHECK(callback_called==1); |
| BOOST_CHECK(fi.get()==42); |
| } |
| |
| void test_wait_for_any_from_range() |
| { |
| unsigned const count=10; |
| for(unsigned i=0;i<count;++i) |
| { |
| boost::packaged_task<int> tasks[count]; |
| boost::unique_future<int> futures[count]; |
| for(unsigned j=0;j<count;++j) |
| { |
| tasks[j]=boost::packaged_task<int>(make_int_slowly); |
| futures[j]=tasks[j].get_future(); |
| } |
| boost::thread(::cast_to_rval(tasks[i])); |
| |
| BOOST_CHECK(boost::wait_for_any(futures,futures)==futures); |
| |
| boost::unique_future<int>* const future=boost::wait_for_any(futures,futures+count); |
| |
| BOOST_CHECK(future==(futures+i)); |
| for(unsigned j=0;j<count;++j) |
| { |
| if(j!=i) |
| { |
| BOOST_CHECK(!futures[j].is_ready()); |
| } |
| else |
| { |
| BOOST_CHECK(futures[j].is_ready()); |
| } |
| } |
| BOOST_CHECK(futures[i].get()==42); |
| } |
| } |
| |
| void test_wait_for_all_from_range() |
| { |
| unsigned const count=10; |
| boost::unique_future<int> futures[count]; |
| for(unsigned j=0;j<count;++j) |
| { |
| boost::packaged_task<int> task(make_int_slowly); |
| futures[j]=task.get_future(); |
| boost::thread(::cast_to_rval(task)); |
| } |
| |
| boost::wait_for_all(futures,futures+count); |
| |
| for(unsigned j=0;j<count;++j) |
| { |
| BOOST_CHECK(futures[j].is_ready()); |
| } |
| } |
| |
| void test_wait_for_all_two_futures() |
| { |
| unsigned const count=2; |
| boost::unique_future<int> futures[count]; |
| for(unsigned j=0;j<count;++j) |
| { |
| boost::packaged_task<int> task(make_int_slowly); |
| futures[j]=task.get_future(); |
| boost::thread(::cast_to_rval(task)); |
| } |
| |
| boost::wait_for_all(futures[0],futures[1]); |
| |
| for(unsigned j=0;j<count;++j) |
| { |
| BOOST_CHECK(futures[j].is_ready()); |
| } |
| } |
| |
| void test_wait_for_all_three_futures() |
| { |
| unsigned const count=3; |
| boost::unique_future<int> futures[count]; |
| for(unsigned j=0;j<count;++j) |
| { |
| boost::packaged_task<int> task(make_int_slowly); |
| futures[j]=task.get_future(); |
| boost::thread(::cast_to_rval(task)); |
| } |
| |
| boost::wait_for_all(futures[0],futures[1],futures[2]); |
| |
| for(unsigned j=0;j<count;++j) |
| { |
| BOOST_CHECK(futures[j].is_ready()); |
| } |
| } |
| |
| void test_wait_for_all_four_futures() |
| { |
| unsigned const count=4; |
| boost::unique_future<int> futures[count]; |
| for(unsigned j=0;j<count;++j) |
| { |
| boost::packaged_task<int> task(make_int_slowly); |
| futures[j]=task.get_future(); |
| boost::thread(::cast_to_rval(task)); |
| } |
| |
| boost::wait_for_all(futures[0],futures[1],futures[2],futures[3]); |
| |
| for(unsigned j=0;j<count;++j) |
| { |
| BOOST_CHECK(futures[j].is_ready()); |
| } |
| } |
| |
| void test_wait_for_all_five_futures() |
| { |
| unsigned const count=5; |
| boost::unique_future<int> futures[count]; |
| for(unsigned j=0;j<count;++j) |
| { |
| boost::packaged_task<int> task(make_int_slowly); |
| futures[j]=task.get_future(); |
| boost::thread(::cast_to_rval(task)); |
| } |
| |
| boost::wait_for_all(futures[0],futures[1],futures[2],futures[3],futures[4]); |
| |
| for(unsigned j=0;j<count;++j) |
| { |
| BOOST_CHECK(futures[j].is_ready()); |
| } |
| } |
| |
| |
| boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) |
| { |
| boost::unit_test_framework::test_suite* test = |
| BOOST_TEST_SUITE("Boost.Threads: futures test suite"); |
| |
| test->add(BOOST_TEST_CASE(test_initial_state)); |
| test->add(BOOST_TEST_CASE(test_waiting_future)); |
| test->add(BOOST_TEST_CASE(test_cannot_get_future_twice)); |
| test->add(BOOST_TEST_CASE(test_set_value_updates_future_state)); |
| test->add(BOOST_TEST_CASE(test_set_value_can_be_retrieved)); |
| test->add(BOOST_TEST_CASE(test_set_value_can_be_moved)); |
| test->add(BOOST_TEST_CASE(test_store_value_from_thread)); |
| test->add(BOOST_TEST_CASE(test_store_exception)); |
| test->add(BOOST_TEST_CASE(test_future_from_packaged_task_is_waiting)); |
| test->add(BOOST_TEST_CASE(test_invoking_a_packaged_task_populates_future)); |
| test->add(BOOST_TEST_CASE(test_invoking_a_packaged_task_twice_throws)); |
| test->add(BOOST_TEST_CASE(test_cannot_get_future_twice_from_task)); |
| test->add(BOOST_TEST_CASE(test_task_stores_exception_if_function_throws)); |
| test->add(BOOST_TEST_CASE(test_void_promise)); |
| test->add(BOOST_TEST_CASE(test_reference_promise)); |
| test->add(BOOST_TEST_CASE(test_task_returning_void)); |
| test->add(BOOST_TEST_CASE(test_task_returning_reference)); |
| test->add(BOOST_TEST_CASE(test_shared_future)); |
| test->add(BOOST_TEST_CASE(test_copies_of_shared_future_become_ready_together)); |
| test->add(BOOST_TEST_CASE(test_shared_future_can_be_move_assigned_from_unique_future)); |
| test->add(BOOST_TEST_CASE(test_shared_future_void)); |
| test->add(BOOST_TEST_CASE(test_shared_future_ref)); |
| test->add(BOOST_TEST_CASE(test_can_get_a_second_future_from_a_moved_promise)); |
| test->add(BOOST_TEST_CASE(test_can_get_a_second_future_from_a_moved_void_promise)); |
| test->add(BOOST_TEST_CASE(test_unique_future_for_move_only_udt)); |
| test->add(BOOST_TEST_CASE(test_unique_future_for_string)); |
| test->add(BOOST_TEST_CASE(test_wait_callback)); |
| test->add(BOOST_TEST_CASE(test_wait_callback_with_timed_wait)); |
| test->add(BOOST_TEST_CASE(test_wait_callback_for_packaged_task)); |
| test->add(BOOST_TEST_CASE(test_packaged_task_can_be_moved)); |
| test->add(BOOST_TEST_CASE(test_destroying_a_promise_stores_broken_promise)); |
| test->add(BOOST_TEST_CASE(test_destroying_a_packaged_task_stores_broken_promise)); |
| test->add(BOOST_TEST_CASE(test_wait_for_either_of_two_futures_1)); |
| test->add(BOOST_TEST_CASE(test_wait_for_either_of_two_futures_2)); |
| test->add(BOOST_TEST_CASE(test_wait_for_either_of_three_futures_1)); |
| test->add(BOOST_TEST_CASE(test_wait_for_either_of_three_futures_2)); |
| test->add(BOOST_TEST_CASE(test_wait_for_either_of_three_futures_3)); |
| test->add(BOOST_TEST_CASE(test_wait_for_either_of_four_futures_1)); |
| test->add(BOOST_TEST_CASE(test_wait_for_either_of_four_futures_2)); |
| test->add(BOOST_TEST_CASE(test_wait_for_either_of_four_futures_3)); |
| test->add(BOOST_TEST_CASE(test_wait_for_either_of_four_futures_4)); |
| test->add(BOOST_TEST_CASE(test_wait_for_either_of_five_futures_1)); |
| test->add(BOOST_TEST_CASE(test_wait_for_either_of_five_futures_2)); |
| test->add(BOOST_TEST_CASE(test_wait_for_either_of_five_futures_3)); |
| test->add(BOOST_TEST_CASE(test_wait_for_either_of_five_futures_4)); |
| test->add(BOOST_TEST_CASE(test_wait_for_either_of_five_futures_5)); |
| test->add(BOOST_TEST_CASE(test_wait_for_either_invokes_callbacks)); |
| test->add(BOOST_TEST_CASE(test_wait_for_any_from_range)); |
| test->add(BOOST_TEST_CASE(test_wait_for_all_from_range)); |
| test->add(BOOST_TEST_CASE(test_wait_for_all_two_futures)); |
| test->add(BOOST_TEST_CASE(test_wait_for_all_three_futures)); |
| test->add(BOOST_TEST_CASE(test_wait_for_all_four_futures)); |
| test->add(BOOST_TEST_CASE(test_wait_for_all_five_futures)); |
| |
| return test; |
| } |