diff --git a/doc/changes.qbk b/doc/changes.qbk index 4b6e5e83..809ed897 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -24,7 +24,10 @@ Fixed Bugs: * [@http://svn.boost.org/trac/boost/ticket/4480 #4480] OpenVMS patches for compiler issues workarounds. * [@http://svn.boost.org/trac/boost/ticket/4819 #4819] boost.thread's documentation misprints. +* [@http://svn.boost.org/trac/boost/ticket/5040 #5040] future.hpp in boost::thread does not compile with /clr. * [@http://svn.boost.org/trac/boost/ticket/5423 #5423] thread issues with C++0x. +* [@http://svn.boost.org/trac/boost/ticket/5502 #5502] race condition between shared_mutex timed_lock and lock_shared. +* [@http://svn.boost.org/trac/boost/ticket/5594 #5594] boost::shared_mutex not fully compatible with Windows CE. * [@http://svn.boost.org/trac/boost/ticket/5617 #5617] boost::thread::id copy ctor. * [@http://svn.boost.org/trac/boost/ticket/5739 #5739] set-but-not-used warnings with gcc-4.6. * [@http://svn.boost.org/trac/boost/ticket/5826 #5826] threads.cpp: resource leak on threads creation failure. @@ -32,6 +35,7 @@ Fixed Bugs: * [@http://svn.boost.org/trac/boost/ticket/5859 #5859] win32 shared_mutex constructor leaks on exceptions. * [@http://svn.boost.org/trac/boost/ticket/6100 #6100] Compute hardware_concurrency() using get_nprocs() on GLIBC systems. +* [@http://svn.boost.org/trac/boost/ticket/6141 #6141] Compilation error when boost.thread and boost.move are used together. * [@http://svn.boost.org/trac/boost/ticket/6168 #6168] recursive_mutex is using wrong config symbol (possible typo). * [@http://svn.boost.org/trac/boost/ticket/6175 #6175] Compile error with SunStudio. * [@http://svn.boost.org/trac/boost/ticket/6200 #6200] patch to have condition_variable and mutex error better handle EINTR. diff --git a/include/boost/thread/detail/config.hpp b/include/boost/thread/detail/config.hpp index da4e288d..b5955066 100644 --- a/include/boost/thread/detail/config.hpp +++ b/include/boost/thread/detail/config.hpp @@ -10,6 +10,15 @@ #include #include + +#if !defined BOOST_THREAD_VERSION +#define BOOST_THREAD_VERSION 1 +#else +#if BOOST_THREAD_VERSION!=1 && BOOST_THREAD_VERSION!=2 +#error "BOOST_THREAD_VERSION must be 1 or 2" +#endif +#endif + #if BOOST_WORKAROUND(__BORLANDC__, < 0x600) # pragma warn -8008 // Condition always true/false # pragma warn -8080 // Identifier declared but never used diff --git a/include/boost/thread/detail/move.hpp b/include/boost/thread/detail/move.hpp index eb21107f..665a0b59 100644 --- a/include/boost/thread/detail/move.hpp +++ b/include/boost/thread/detail/move.hpp @@ -6,15 +6,20 @@ #ifndef BOOST_THREAD_MOVE_HPP #define BOOST_THREAD_MOVE_HPP +#include #ifndef BOOST_NO_SFINAE #include #include +#include #endif +#include + #include namespace boost { + namespace detail { template @@ -41,18 +46,19 @@ namespace boost #ifndef BOOST_NO_SFINAE template - typename enable_if >, detail::thread_move_t >::type move(T& t) + typename enable_if >, boost::detail::thread_move_t >::type move(T& t) { - return detail::thread_move_t(t); + return boost::detail::thread_move_t(t); } #endif - + template - detail::thread_move_t move(detail::thread_move_t t) + boost::detail::thread_move_t move(boost::detail::thread_move_t t) { return t; } - + + } #include diff --git a/include/boost/thread/detail/thread.hpp b/include/boost/thread/detail/thread.hpp index 7863c2f9..7ac342bf 100644 --- a/include/boost/thread/detail/thread.hpp +++ b/include/boost/thread/detail/thread.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -444,6 +445,7 @@ namespace boost { if(x.thread_data) { + io::ios_flags_saver ifs( os ); return os<< std::hex << x.thread_data; } else @@ -519,6 +521,13 @@ namespace boost void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*); } +#ifdef BOOST_NO_RVALUE_REFERENCES + template <> + struct has_move_emulation_enabled_aux + : BOOST_MOVE_BOOST_NS::integral_constant + {}; +#endif + namespace this_thread { template diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index 5ea12026..bd871583 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -413,13 +413,19 @@ namespace boost struct all_futures_lock { - count_type count; +#ifdef _MANAGED + typedef std::ptrdiff_t count_type_portable; +#else + typedef count_type count_type_portable; +#endif + count_type_portable count; + boost::scoped_array > locks; all_futures_lock(std::vector& futures): count(futures.size()),locks(new boost::unique_lock[count]) { - for(count_type i=0;i(futures[i].future->mutex).move(); @@ -436,7 +442,7 @@ namespace boost void unlock() { - for(count_type i=0;i + struct has_move_emulation_enabled_aux > + : BOOST_MOVE_BOOST_NS::integral_constant + {}; +#endif + template class shared_future { @@ -906,6 +919,13 @@ namespace boost }; +#ifdef BOOST_NO_RVALUE_REFERENCES + template + struct has_move_emulation_enabled_aux > + : BOOST_MOVE_BOOST_NS::integral_constant + {}; +#endif + template class promise { @@ -1172,6 +1192,13 @@ namespace boost }; +#ifdef BOOST_NO_RVALUE_REFERENCES + template + struct has_move_emulation_enabled_aux > + : BOOST_MOVE_BOOST_NS::integral_constant + {}; +#endif + namespace detail { template @@ -1220,9 +1247,15 @@ namespace boost task_object(F const& f_): f(f_) {} +#ifndef BOOST_NO_RVALUE_REFERENCES + task_object(F&& f_): + f(f_) + {} +#else task_object(boost::detail::thread_move_t f_): f(f_) {} +#endif void do_run() { @@ -1245,9 +1278,15 @@ namespace boost task_object(F const& f_): f(f_) {} +#ifndef BOOST_NO_RVALUE_REFERENCES + task_object(F&& f_): + f(f_) + {} +#else task_object(boost::detail::thread_move_t f_): f(f_) {} +#endif void do_run() { @@ -1289,10 +1328,17 @@ namespace boost task(new detail::task_object(f)),future_obtained(false) {} +#ifndef BOOST_NO_RVALUE_REFERENCES + template + explicit packaged_task(F&& f): + task(new detail::task_object(f)),future_obtained(false) + {} +#else template explicit packaged_task(boost::detail::thread_move_t f): task(new detail::task_object(f)),future_obtained(false) {} +#endif // template // explicit packaged_task(F const& f, Allocator a); @@ -1341,7 +1387,7 @@ namespace boost } #endif - void swap(packaged_task& other) + void swap(packaged_task& other) { task.swap(other.task); std::swap(future_obtained,other.future_obtained); @@ -1384,6 +1430,13 @@ namespace boost }; +#ifdef BOOST_NO_RVALUE_REFERENCES + template + struct has_move_emulation_enabled_aux > + : BOOST_MOVE_BOOST_NS::integral_constant + {}; +#endif + } diff --git a/include/boost/thread/locks.hpp b/include/boost/thread/locks.hpp index f159b7f9..26012707 100644 --- a/include/boost/thread/locks.hpp +++ b/include/boost/thread/locks.hpp @@ -518,6 +518,13 @@ namespace boost } #endif +#ifdef BOOST_NO_RVALUE_REFERENCES + template + struct has_move_emulation_enabled_aux > + : BOOST_MOVE_BOOST_NS::integral_constant + {}; +#endif + template class shared_lock { @@ -553,7 +560,9 @@ namespace boost { timed_lock(target_time); } +#ifndef BOOST_NO_RVALUE_REFERENCES +#else shared_lock(detail::thread_move_t > other): m(other->m),is_locked(other->is_locked) { @@ -614,6 +623,7 @@ namespace boost swap(temp); return *this; } +#endif #ifndef BOOST_NO_RVALUE_REFERENCES void swap(shared_lock&& other) @@ -709,6 +719,14 @@ namespace boost }; +#ifdef BOOST_NO_RVALUE_REFERENCES + template + struct has_move_emulation_enabled_aux > + : BOOST_MOVE_BOOST_NS::integral_constant + {}; +#endif + + #ifndef BOOST_NO_RVALUE_REFERENCES template void swap(shared_lock&& lhs,shared_lock&& rhs) @@ -758,7 +776,7 @@ namespace boost { try_lock(); } -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES upgrade_lock(upgrade_lock&& other): m(other.m),is_locked(other.is_locked) { @@ -893,6 +911,12 @@ namespace boost friend class unique_lock; }; +#ifdef BOOST_NO_RVALUE_REFERENCES + template + struct has_move_emulation_enabled_aux > + : BOOST_MOVE_BOOST_NS::integral_constant + {}; +#endif #ifndef BOOST_NO_RVALUE_REFERENCES template @@ -938,7 +962,7 @@ namespace boost } } -#ifdef BOOST_HAS_RVALUE_REFS +#ifndef BOOST_NO_RVALUE_REFERENCES upgrade_to_unique_lock(upgrade_to_unique_lock&& other): source(other.source),exclusive(move(other.exclusive)) { @@ -985,6 +1009,13 @@ namespace boost } }; +#ifdef BOOST_NO_RVALUE_REFERENCES + template + struct has_move_emulation_enabled_aux > + : BOOST_MOVE_BOOST_NS::integral_constant + {}; +#endif + namespace detail { template diff --git a/include/boost/thread/pthread/shared_mutex.hpp b/include/boost/thread/pthread/shared_mutex.hpp index bc262828..56e209ac 100644 --- a/include/boost/thread/pthread/shared_mutex.hpp +++ b/include/boost/thread/pthread/shared_mutex.hpp @@ -27,7 +27,7 @@ namespace boost bool upgrade; bool exclusive_waiting_blocked; }; - + state_data state; @@ -41,7 +41,7 @@ namespace boost exclusive_cond.notify_one(); shared_cond.notify_all(); } - + public: shared_mutex() @@ -58,7 +58,7 @@ namespace boost { boost::this_thread::disable_interruption do_not_disturb; boost::mutex::scoped_lock lk(state_change); - + while(state.exclusive || state.exclusive_waiting_blocked) { shared_cond.wait(lk); @@ -69,7 +69,7 @@ namespace boost bool try_lock_shared() { boost::mutex::scoped_lock lk(state_change); - + if(state.exclusive || state.exclusive_waiting_blocked) { return false; @@ -85,7 +85,7 @@ namespace boost { boost::this_thread::disable_interruption do_not_disturb; boost::mutex::scoped_lock lk(state_change); - + while(state.exclusive || state.exclusive_waiting_blocked) { if(!shared_cond.timed_wait(lk,timeout)) @@ -107,7 +107,7 @@ namespace boost { boost::mutex::scoped_lock lk(state_change); bool const last_reader=!--state.shared_count; - + if(last_reader) { if(state.upgrade) @@ -128,7 +128,7 @@ namespace boost { boost::this_thread::disable_interruption do_not_disturb; boost::mutex::scoped_lock lk(state_change); - + while(state.shared_count || state.exclusive) { state.exclusive_waiting_blocked=true; @@ -150,7 +150,7 @@ namespace boost if(state.shared_count || state.exclusive) { state.exclusive_waiting_blocked=false; - exclusive_cond.notify_one(); + release_waiters(); return false; } break; @@ -169,7 +169,7 @@ namespace boost bool try_lock() { boost::mutex::scoped_lock lk(state_change); - + if(state.shared_count || state.exclusive) { return false; @@ -179,7 +179,7 @@ namespace boost state.exclusive=true; return true; } - + } void unlock() @@ -248,7 +248,7 @@ namespace boost boost::mutex::scoped_lock lk(state_change); state.upgrade=false; bool const last_reader=!--state.shared_count; - + if(last_reader) { state.exclusive_waiting_blocked=false; @@ -278,7 +278,7 @@ namespace boost state.exclusive_waiting_blocked=false; release_waiters(); } - + void unlock_and_lock_shared() { boost::mutex::scoped_lock lk(state_change); @@ -287,7 +287,7 @@ namespace boost state.exclusive_waiting_blocked=false; release_waiters(); } - + void unlock_upgrade_and_lock_shared() { boost::mutex::scoped_lock lk(state_change); diff --git a/include/boost/thread/win32/shared_mutex.hpp b/include/boost/thread/win32/shared_mutex.hpp index 06675139..aee40399 100644 --- a/include/boost/thread/win32/shared_mutex.hpp +++ b/include/boost/thread/win32/shared_mutex.hpp @@ -337,7 +337,12 @@ namespace boost { return true; } - unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,true,::boost::detail::get_milliseconds_until(wait_until)); + #ifndef UNDER_CE + const bool wait_all = true; + #else + const bool wait_all = false; + #endif + unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until)); if(wait_res==detail::win32::timeout) { for(;;) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index e924e9b1..d1d61179 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -62,4 +62,29 @@ rule thread-run ( sources ) [ compile-fail no_implicit_move_from_lvalue_thread.cpp ] [ compile-fail no_implicit_assign_from_lvalue_thread.cpp ] ; + + + #explicit tickets ; + test-suite tickets + : + [ thread-run test_6170.cpp ] + ; + + + explicit oth_tickets ; + test-suite oth_tickets + : + [ thread-run test_2501.cpp ] + [ thread-run test_4521.cpp ] + [ thread-run test_4648.cpp ] + [ thread-run test_4882.cpp ] + [ thread-run test_5351.cpp ] + [ thread-run test_5502.cpp ] + [ thread-run test_5542_1.cpp ] + [ thread-run test_5542_2.cpp ] + [ thread-run test_5542_3.cpp ] + [ thread-run test_6130.cpp ] + [ thread-run test_6174.cpp ] + ; + } diff --git a/test/test_2501.cpp b/test/test_2501.cpp new file mode 100644 index 00000000..50913386 --- /dev/null +++ b/test/test_2501.cpp @@ -0,0 +1,10 @@ +#include + +int main() { + + boost::shared_mutex mtx; boost::upgrade_lock lk(mtx); + + boost::upgrade_to_unique_lock lk2(lk); + + return 0; +} diff --git a/test/test_4521.cpp b/test/test_4521.cpp new file mode 100644 index 00000000..24e1b165 --- /dev/null +++ b/test/test_4521.cpp @@ -0,0 +1,21 @@ +#include + +int calculate_the_answer_to_life_the_universe_and_everything() +{ + return 42; +} + +int main() { +boost::packaged_task pt(calculate_the_answer_to_life_the_universe_and_everything); +boost::unique_future fi=pt.get_future(); + +boost::thread task(boost::move(pt)); // launch task on a thread + +fi.wait(); // wait for it to finish + +//assert(fi.is_ready()); +//assert(fi.has_value()); +//assert(!fi.has_exception()); +//assert(fi.get_state()==boost::future_state::ready); +//assert(fi.get()==42); +} diff --git a/test/test_4648.cpp b/test/test_4648.cpp new file mode 100644 index 00000000..b0f95f8d --- /dev/null +++ b/test/test_4648.cpp @@ -0,0 +1,42 @@ +#include +#include +#include + +class boostThreadLocksTest +{ +public: + boost::shared_mutex myMutex; + //boost::upgrade_lock myLock; + static int firstFunction(boostThreadLocksTest *pBoostThreadLocksTest); + static int secondFunction(boostThreadLocksTest *pBoostThreadLocksTest, + boost::upgrade_lock& upgr); + boostThreadLocksTest() + :myMutex() + //, myLock(myMutex,boost::defer_lock_t()) + {}; +}; + +int boostThreadLocksTest::firstFunction(boostThreadLocksTest *pBoostThreadLocksTest) +{ + std::cout<<"Entering "< myLock(pBoostThreadLocksTest->myMutex); + pBoostThreadLocksTest->secondFunction(pBoostThreadLocksTest, myLock); + std::cout<<"Returned From Call "<& upgr) { + std::cout<<"Before Exclusive Locking "< localUniqueLock(upgr); + std::cout<<"After Exclusive Locking "< +#include + +#include + +boost::shared_mutex mutex; + +void thread() +{ + std::cout << __FILE__ << ":" << __LINE__ << std::endl; + try + { + for (int i =0; i<10; ++i) + { + boost::system_time timeout = boost::get_system_time() + boost::posix_time::milliseconds(50); + + if (mutex.timed_lock(timeout)) + { + std::cout << __FILE__ << ":" << __LINE__ << std::endl; + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + mutex.unlock(); + std::cout << __FILE__ << ":" << __LINE__ << std::endl; + } + } + } + catch (boost::lock_error& le) + { + std::cerr << "lock_error exception\n"; + } + std::cout << __FILE__ << ":" << __LINE__ << std::endl; +} + +int main() +{ + std::cout << __FILE__ << ":" << __LINE__ << std::endl; + const int nrThreads = 20; + boost::thread* threads[nrThreads]; + + for (int i = 0; i < nrThreads; ++i) + threads[i] = new boost::thread(&thread); + + for (int i = 0; i < nrThreads; ++i) + { + threads[i]->join(); + std::cout << __FILE__ << ":" << __LINE__ << std::endl; + delete threads[i]; + } + std::cout << __FILE__ << ":" << __LINE__ << std::endl; + return 0; +} diff --git a/test/test_5351.cpp b/test/test_5351.cpp new file mode 100644 index 00000000..543bb34c --- /dev/null +++ b/test/test_5351.cpp @@ -0,0 +1,45 @@ +#include +#include +#include +#include + +using namespace boost::posix_time; +using namespace boost; + +int foo() +{ + this_thread::sleep(seconds(10)); + return 0; +} + + +int main(int argc, char** argv) +{ + boost::packaged_task pt(&foo); + boost::unique_future fi = pt.get_future(); + boost::thread task(boost::move(pt)); // launch task on a thread + + task.interrupt(); + + try + { + int v = fi.get(); + } + catch (boost::thread_interrupted& exc) + { + std::cout << "OK: " << std::endl; + return 0; + } + catch (boost::exception& exc) + { + std::cout << __LINE__ << " ERROR: " << boost::diagnostic_information(exc) << std::endl; + return 1; + } + catch (...) + { + std::cout << __LINE__ << " ERROR: " << std::endl; + return 2; + } + std::cout << __LINE__ << " ERROR: " << std::endl; + return 3; +} diff --git a/test/test_5502.cpp b/test/test_5502.cpp new file mode 100644 index 00000000..3baf9bb4 --- /dev/null +++ b/test/test_5502.cpp @@ -0,0 +1,86 @@ +// bm.cpp + +// g++ test.cpp -lboost_thread-mt && ./a.out + +// the ration of XXX and YYY determines +// if this works or deadlocks +int XXX = 20; +int YYY = 10; + +#include +#include + +#include +#include +#include + +using namespace std; + +void sleepmillis(useconds_t miliis) +{ + usleep(miliis * 1000); +} + +void worker1(boost::shared_mutex * lk, int * x) +{ + (*x)++; // 1 + cout << "lock b try " << *x << endl; + while (1) + { + if (lk->timed_lock(boost::posix_time::milliseconds(XXX))) break; + sleepmillis(YYY); + } + cout << "lock b got " << *x << endl; + (*x)++; // 2 + lk->unlock(); +} + +void worker2(boost::shared_mutex * lk, int * x) +{ + cout << "lock c try" << endl; + lk->lock_shared(); + (*x)++; + cout << "lock c got" << endl; + lk->unlock_shared(); + cout << "lock c unlocked" << endl; + (*x)++; +} + +int main() +{ + + // create + boost::shared_mutex* lk = new boost::shared_mutex(); + + // read lock + cout << "lock a" << endl; + lk->lock_shared(); + + int x1 = 0; + boost::thread t1(boost::bind(worker1, lk, &x1)); + while (!x1) + ; + BOOST_TEST(x1 == 1); + sleepmillis(500); + BOOST_TEST(x1 == 1); + + int x2 = 0; + boost::thread t2(boost::bind(worker2, lk, &x2)); + t2.join(); + BOOST_TEST(x2 == 2); + + lk->unlock_shared(); + cout << "unlock a" << endl; + + for (int i = 0; i < 2000; i++) + { + if (x1 == 2) break; + sleepmillis(10); + } + + BOOST_TEST(x1 == 2); + t1.join(); + delete lk; + + return 0; +} diff --git a/test/test_5542_1.cpp b/test/test_5542_1.cpp new file mode 100644 index 00000000..79dfd60d --- /dev/null +++ b/test/test_5542_1.cpp @@ -0,0 +1,62 @@ +#include +#include + +class Worker +{ +public: + + Worker() + { + // the thread is not-a-thread until we call start() + } + + void start(int N) + { + std::cout << "start\n"; + m_Thread = boost::thread(&Worker::processQueue, this, N); + std::cout << "started\n"; + } + + void join() + { + m_Thread.join(); + } + + void processQueue(unsigned N) + { + float ms = N * 1e3; + boost::posix_time::milliseconds workTime(ms); + + std::cout << "Worker: started, will work for " + << ms << "ms" + << std::endl; + + // We're busy, honest! + boost::this_thread::sleep(workTime); + + std::cout << "Worker: completed" << std::endl; + } + +private: + + boost::thread m_Thread; +}; + +int main(int argc, char* argv[]) +{ + std::cout << "main: startup" << std::endl; + + Worker worker; + + std::cout << "main: create worker" << std::endl; + + worker.start(3); + + std::cout << "main: waiting for thread" << std::endl; + + worker.join(); + + std::cout << "main: done" << std::endl; + + return 0; +} diff --git a/test/test_5542_2.cpp b/test/test_5542_2.cpp new file mode 100644 index 00000000..c48ef4ea --- /dev/null +++ b/test/test_5542_2.cpp @@ -0,0 +1,11 @@ +#include + +void run_thread() { + return; +} + +int main() { + boost::thread t(run_thread); + return 0; +} + diff --git a/test/test_5542_3.cpp b/test/test_5542_3.cpp new file mode 100644 index 00000000..0c1ac40b --- /dev/null +++ b/test/test_5542_3.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +void workerFunc() +{ + boost::posix_time::seconds workTime(3); + + std::cout << "Worker: running" << std::endl; + + // Pretend to do something useful... + boost::this_thread::sleep(workTime); + + std::cout << "Worker: finished" << std::endl; +} + +int main(int argc, char* argv[]) +{ + std::cout << "main: startup" << std::endl; + + boost::thread workerThread(workerFunc); + + std::cout << "main: waiting for thread" << std::endl; + + workerThread.join(); + + std::cout << "main: done" << std::endl; + + return 0; +} diff --git a/test/test_6130.cpp b/test/test_6130.cpp new file mode 100644 index 00000000..3ef1f183 --- /dev/null +++ b/test/test_6130.cpp @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include + +boost::mutex mtx; +boost::condition_variable cv; + +int main() +{ + for (int i=0; i<3; ++i) { + const time_t wait_time = ::time(0)+1; + + boost::mutex::scoped_lock lk(mtx); + const bool res = cv.timed_wait(lk, boost::posix_time::from_time_t(wait_time)); + const time_t end_time = ::time(0); + assert(end_time >= wait_time); + std::cerr << end_time - wait_time << " OK\n"; + } + return 0; +} diff --git a/test/test_6170.cpp b/test/test_6170.cpp new file mode 100644 index 00000000..6f2f28fd --- /dev/null +++ b/test/test_6170.cpp @@ -0,0 +1,26 @@ +#include +#include + +// Including this will cause ambiguous errors in boost::move +#include + +using namespace boost; + +typedef upgrade_lock auto_upgrade_lock; +typedef upgrade_to_unique_lock auto_upgrade_unique_lock; + +void testUpgrade(void) +{ + shared_mutex mtx; + auto_upgrade_lock lock(mtx); + // Do some read-only stuff + + auto_upgrade_unique_lock writeLock(lock); + // Do some write-only stuff with the upgraded lock +} + +int main() +{ + testUpgrade(); + return 0; +} \ No newline at end of file diff --git a/test/test_6174.cpp b/test/test_6174.cpp new file mode 100644 index 00000000..b3c14eca --- /dev/null +++ b/test/test_6174.cpp @@ -0,0 +1,35 @@ + + +#include +#include + +#ifndef BOOST_NO_RVALUE_REFERENCES +struct MovableButNonCopyable { +#ifndef BOOST_NO_DEFAULTED_FUNCTIONS + MovableButNonCopyable() = default; + MovableButNonCopyable(MovableButNonCopyable const&) = delete; + MovableButNonCopyable& operator=(MovableButNonCopyable const&) = delete; + MovableButNonCopyable(MovableButNonCopyable&&) = default; + MovableButNonCopyable& operator=(MovableButNonCopyable&&) = default; +#else + MovableButNonCopyable() {}; + MovableButNonCopyable(MovableButNonCopyable&&) {}; + MovableButNonCopyable& operator=(MovableButNonCopyable&&) { + return *this; + }; +private: + MovableButNonCopyable(MovableButNonCopyable const&); + MovableButNonCopyable& operator=(MovableButNonCopyable const&); +#endif +}; +int main() +{ + boost::packaged_task(MovableButNonCopyable()); + return 0; +} +#else +int main() +{ + return 0; +} +#endif diff --git a/test/test_move_function.cpp b/test/test_move_function.cpp index d28b6524..fa139e88 100644 --- a/test/test_move_function.cpp +++ b/test/test_move_function.cpp @@ -1,6 +1,6 @@ // Copyright (C) 2007-8 Anthony Williams // -// Distributed under the Boost Software License, Version 1.0. (See accompanying +// 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 #include @@ -89,10 +89,17 @@ namespace user_test_ns } bool move_called=false; - + struct nc: public boost::shared_ptr { +#ifndef BOOST_NO_RVALUE_REFERENCES + nc() {} + nc(nc&&) + { + move_called=true; + } +#endif nc move() { move_called=true; @@ -101,10 +108,24 @@ namespace user_test_ns }; } +#ifdef BOOST_NO_RVALUE_REFERENCES +namespace boost +{ + template <> + struct has_move_emulation_enabled_aux + : BOOST_MOVE_BOOST_NS::integral_constant + {}; +} +#endif + void test_move_for_user_defined_type_unaffected() { user_test_ns::nc src; +#ifndef BOOST_NO_RVALUE_REFERENCES + user_test_ns::nc dest=boost::move(src); +#else user_test_ns::nc dest=move(src); +#endif BOOST_CHECK(user_test_ns::move_called); }