diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index ad8456a..9e5de6b 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -1383,7 +1383,7 @@ All the mutex types from [*Boost.Interprocess] implement the following operation [*Throws:] *interprocess_exception* on error. -[blurb ['[*bool timed_lock(const boost::posix_time::ptime &abs_time)]]] +[blurb ['[*template bool timed_lock(const TimePoint &abs_time)]]] [*Effects:] The calling thread will try to obtain exclusive ownership of the mutex if it can do so in until the specified time is reached. If the mutex supports recursive locking, the mutex must be unlocked the same number of times it is locked. @@ -1399,8 +1399,8 @@ All the mutex types from [*Boost.Interprocess] implement the following operation [*Throws:] An exception derived from *interprocess_exception* on error. -[important `boost::posix_time::ptime` absolute time points used by Boost.Interprocess synchronization mechanisms -are UTC time points, not local time points] +[important Boost.Interprocess timed synchronization mechanisms support several timepoints: `boost::posix_time::ptime` absolute UTC time points, + `boost::chrono` and `std::chrono` timepoints. Additionally Interprocess' mutexes meet standard C++ `TimedLockable` requirements for std-compatibility] [endsect] @@ -1499,8 +1499,8 @@ try_lock, timed_lock a mutex or not to lock it at all. For more information, check the [classref boost::interprocess::scoped_lock scoped_lock's reference]. -[important `boost::posix_time::ptime` absolute time points used by Boost.Interprocess synchronization mechanisms -are UTC time points, not local time points] +[important Boost.Interprocess timed synchronization operations support several timepoints: `boost::posix_time::ptime` absolute UTC time points, + `boost::chrono` and `std::chrono` timepoints] [endsect] @@ -1857,7 +1857,7 @@ If it has to wait, returns false. [*Throws:] *interprocess_exception* on error. -[blurb ['[*bool timed_lock(const boost::posix_time::ptime &abs_time)]]] +[blurb ['[*template bool timed_lock(const TimePoint &abs_time)]]] [*Effects:] The calling thread tries to acquire exclusive ownership of the mutex @@ -1902,7 +1902,7 @@ If it has to wait, returns false. [*Throws:] *interprocess_exception* on error. -[blurb ['[*bool timed_lock_sharable(const boost::posix_time::ptime &abs_time)]]] +[blurb ['[*template bool timed_lock_sharable(const TimePoint &abs_time)]]] [*Effects:] The calling thread tries to acquire sharable ownership of the mutex @@ -1947,7 +1947,7 @@ If it has to wait, returns false. [*Throws:] *interprocess_exception* on error. -[blurb ['[*bool timed_lock_upgradable(const boost::posix_time::ptime &abs_time)]]] +[blurb ['[*template bool timed_lock_upgradable(const TimePoint &abs_time)]]] [*Effects:] The calling thread tries to acquire upgradable ownership of the mutex @@ -2019,7 +2019,9 @@ it will maintain upgradable ownership. [*Returns:] If acquires exclusive ownership, returns true. Otherwise returns false. -[*Throws:] An exception derived from *interprocess_exception* on error.[blurb ['[*bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &abs_time)]]] +[*Throws:] An exception derived from *interprocess_exception* on error. + +[blurb ['[*template bool timed_unlock_upgradable_and_lock(const TimePoint &abs_time)]]] [*Precondition:] The thread must have upgradable ownership of the mutex. @@ -2042,7 +2044,9 @@ but it will maintain sharable ownership. [*Returns:] If acquires exclusive ownership, returns true. Otherwise returns false. -[*Throws:] An exception derived from *interprocess_exception* on error.[blurb ['[*bool try_unlock_sharable_and_lock_upgradable()]]] +[*Throws:] An exception derived from *interprocess_exception* on error. + +[blurb ['[*bool try_unlock_sharable_and_lock_upgradable()]]] [*Precondition:] The thread must have sharable ownership of the mutex. @@ -2055,8 +2059,8 @@ returns false. [*Throws:] An exception derived from *interprocess_exception* on error. -[important `boost::posix_time::ptime` absolute time points used by Boost.Interprocess synchronization mechanisms -are UTC time points, not local time points] +[important Boost.Interprocess timed synchronization mechanisms support several timepoints: `boost::posix_time::ptime` absolute UTC time points, + `boost::chrono` and `std::chrono` timepoints.] [endsect] @@ -2096,6 +2100,8 @@ Boost.Interprocess offers the following upgradable mutex types: * [classref boost::interprocess::named_upgradable_mutex named_upgradable_mutex]: A non-recursive, named upgradable mutex. +[important Interprocess shared mutexes meet standard C++ `SharedTimedMutex` requirements for std-compatibility] + [endsect] [section:sharable_upgradable_locks Sharable Lock And Upgradable Lock] @@ -2234,8 +2240,8 @@ upgradable mutex is always unlocked when an exception occurs. [classref boost::interprocess::sharable_lock sharable_lock] offer more features and operations, see their reference for more informations -[important `boost::posix_time::ptime` absolute time points used by Boost.Interprocess synchronization mechanisms -are UTC time points, not local time points] +[important Boost.Interprocess timed synchronization mechanisms support several timepoints: `boost::posix_time::ptime` absolute UTC time points, + `boost::chrono` and `std::chrono` timepoints.] [endsect] @@ -2392,8 +2398,8 @@ is permitted: scoped_lock e_lock(move(s_lock, try_to_lock)); } -[important `boost::posix_time::ptime` absolute time points used by Boost.Interprocess synchronization mechanisms -are UTC time points, not local time points] +[important Boost.Interprocess timed synchronization mechanisms support several timepoints: `boost::posix_time::ptime` absolute UTC time points, + `boost::chrono` and `std::chrono` timepoints.] [endsect] @@ -2654,7 +2660,7 @@ If it has to wait, returns false. [*Throws:] *interprocess_exception* on error. -[blurb ['[*bool timed_lock(const boost::posix_time::ptime &abs_time)]]] +[blurb ['[*template bool timed_lock(const TimePoint &abs_time)]]] [*Effects:] The calling thread tries to acquire exclusive ownership of the file lock @@ -2695,7 +2701,7 @@ If it has to wait, returns false. [*Throws:] *interprocess_exception* on error. -[blurb ['[*bool timed_lock_sharable(const boost::posix_time::ptime &abs_time)]]] +[blurb ['[*template bool timed_lock_sharable(const TimePoint &abs_time)]]] [*Effects:] The calling thread tries to acquire sharable ownership of the file lock @@ -2718,8 +2724,8 @@ returns false. For more file locking methods, please [classref boost::interprocess::file_lock file_lock reference]. -[important `boost::posix_time::ptime` absolute time points used by Boost.Interprocess synchronization mechanisms -are UTC time points, not local time points] +[important Boost.Interprocess timed synchronization mechanisms support several timepoints: `boost::posix_time::ptime` absolute UTC time points, + `boost::chrono` and `std::chrono` timepoints.] [endsect] @@ -6797,7 +6803,12 @@ thank them: [section:release_notes_boost_1_78_00 Boost 1.78 Release] +* Mutexes and condition variables now additionally offer a standard C++-like interface to allow reusing code that + is already working with standard thread utilities. E.g.: mutexes meet `TimedLockable` requirements and condition + variables implement `wait_until/wait_for` operations. + * Fixed bugs: + * [@https://github.com/boostorg/interprocess/issues/149 GitHub #149 (['"interprocess_condition_any::timed_wait update"])]. * [@https://github.com/boostorg/interprocess/issues/145 GitHub #145 (['"1.76 now requires unicode paths on windows"])]. [endsect] diff --git a/include/boost/interprocess/detail/timed_utils.hpp b/include/boost/interprocess/detail/timed_utils.hpp index 72022f9..7479832 100644 --- a/include/boost/interprocess/detail/timed_utils.hpp +++ b/include/boost/interprocess/detail/timed_utils.hpp @@ -166,6 +166,15 @@ class ustime ustime operator + (const usduration &other) { ustime r(*this); r += other; return r; } + ustime &operator -= (const usduration &other) + { m_microsecs -= other.m_microsecs; return *this; } + + ustime operator - (const usduration &other) + { ustime r(*this); r -= other; return r; } + + friend usduration operator - (const ustime &l, const ustime &r) + { return usduration(l.m_microsecs - r.m_microsecs); } + bool operator < (const ustime &other) const { return m_microsecs < other.m_microsecs; } @@ -296,6 +305,22 @@ inline bool is_pos_infinity(const TimePoint &, typename disable_if_ptime +inline ustime duration_to_timepoint(const Duration &dur, typename enable_if_ptime::type* = 0) +{ + return dur.is_pos_infinity(); +} + +template +inline bool duration_to_timepoint(const Duration &, typename disable_if_ptime::type* = 0) +{ + return false; +} +*/ + +// duration_to_milliseconds + template inline boost::uint64_t duration_to_milliseconds(const Duration &abs_time, typename enable_if_ptime_duration::type* = 0) { @@ -309,6 +334,34 @@ inline boost::uint64_t duration_to_milliseconds(const Duration &d, typename enab return static_cast(d.count()*factor); } +inline boost::uint64_t duration_to_milliseconds(const usduration &d) +{ + return d.get_microsecs()/1000; +} + +// duration_to_usduration + +template +inline usduration duration_to_usduration(const Duration &d, typename enable_if_ptime_duration::type* = 0) +{ + return usduration(d.total_microseconds()); +} + +template +inline usduration duration_to_usduration(const Duration &d, typename enable_if_duration::type* = 0) +{ + const double factor = double(Duration::period::num)*1000000.0/double(Duration::period::den); + return usduration(static_cast(d.count()*factor)); +} + +// duration_to_ustime + +template +inline ustime duration_to_ustime(const Duration &d) +{ + return microsec_clock::universal_time() + (duration_to_usduration)(d); +} + } //namespace ipcdetail { } //namespace interprocess { diff --git a/include/boost/interprocess/sync/cv_status.hpp b/include/boost/interprocess/sync/cv_status.hpp new file mode 100644 index 0000000..afbcdf6 --- /dev/null +++ b/include/boost/interprocess/sync/cv_status.hpp @@ -0,0 +1,29 @@ +// cv_status.hpp +// +// Copyright (C) 2011 Vicente J. Botet Escriba +// Copyright (C) 2021 Ion Gaztanaga +// +// 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) + +#ifndef BOOST_INTERPROCESS_CV_STATUS_HPP +#define BOOST_INTERPROCESS_CV_STATUS_HPP + +#include + +namespace boost { +namespace interprocess { + + // enum class cv_status; + BOOST_SCOPED_ENUM_DECLARE_BEGIN(cv_status) + { + no_timeout, + timeout + } + BOOST_SCOPED_ENUM_DECLARE_END(cv_status) + +} //namespace interprocess +} //namespace boost + +#endif // header diff --git a/include/boost/interprocess/sync/file_lock.hpp b/include/boost/interprocess/sync/file_lock.hpp index 8c3fc79..a147837 100644 --- a/include/boost/interprocess/sync/file_lock.hpp +++ b/include/boost/interprocess/sync/file_lock.hpp @@ -138,6 +138,16 @@ class file_lock template bool timed_lock(const TimePoint &abs_time); + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(ipcdetail::duration_to_ustime(dur)); } + //!Precondition: The thread must have exclusive ownership of the mutex. //!Effects: The calling thread releases the exclusive ownership of the mutex. //!Throws: An exception derived from interprocess_exception on error. @@ -157,6 +167,11 @@ class file_lock //! an exception could be thrown. void lock_sharable(); + //!Same as `lock_sharable` but with a std-compatible interface + //! + void lock_shared() + { this->lock_sharable(); } + //!Effects: The calling thread tries to acquire sharable ownership of the mutex //! without waiting. If no other thread has exclusive ownership of the //! mutex this succeeds. @@ -165,6 +180,11 @@ class file_lock //!Throws: interprocess_exception on error. bool try_lock_sharable(); + //!Same as `try_lock_sharable` but with a std-compatible interface + //! + bool try_lock_shared() + { return this->try_lock_sharable(); } + //!Effects: The calling thread tries to acquire sharable ownership of the mutex //! waiting if necessary until no other thread has exclusive ownership of //! the mutex or abs_time is reached. @@ -173,10 +193,26 @@ class file_lock template bool timed_lock_sharable(const TimePoint &abs_time); + //!Same as `timed_lock_sharable`, but this function is modeled after the + //!standard library interface. + template bool try_lock_shared_until(const TimePoint &abs_time) + { return this->timed_lock_sharable(abs_time); } + + //!Same as `timed_lock_sharable`, but this function is modeled after the + //!standard library interface. + template bool try_lock_shared_for(const Duration &dur) + { return this->timed_lock_sharable(ipcdetail::duration_to_ustime(dur)); } + //!Precondition: The thread must have sharable ownership of the mutex. //!Effects: The calling thread releases the sharable ownership of the mutex. //!Throws: An exception derived from interprocess_exception on error. void unlock_sharable(); + + //!Same as `unlock_sharable` but with a std-compatible interface + //! + void unlock_shared() + { this->unlock_sharable(); } + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) private: file_handle_t m_file_hnd; diff --git a/include/boost/interprocess/sync/interprocess_condition.hpp b/include/boost/interprocess/sync/interprocess_condition.hpp index 18d56e5..24ca5b5 100644 --- a/include/boost/interprocess/sync/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/interprocess_condition.hpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -129,6 +130,30 @@ class interprocess_condition return m_condition.timed_wait(internal_lock, abs_time, pred); } + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template + cv_status wait_until(L& lock, const TimePoint &abs_time) + { return this->timed_wait(lock, abs_time) ? cv_status::no_timeout : cv_status::timeout; } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template + bool wait_until(L& lock, const TimePoint &abs_time, Pr pred) + { return this->timed_wait(lock, abs_time, pred); } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface and uses relative timeouts. + template + cv_status wait_for(L& lock, const Duration &dur) + { return this->wait_until(lock, ipcdetail::duration_to_ustime(dur)); } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface and uses relative timeouts + template + bool wait_for(L& lock, const Duration &dur, Pr pred) + { return this->wait_until(lock, ipcdetail::duration_to_ustime(dur), pred); } + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) private: diff --git a/include/boost/interprocess/sync/interprocess_condition_any.hpp b/include/boost/interprocess/sync/interprocess_condition_any.hpp index 6576dd6..6b076a9 100644 --- a/include/boost/interprocess/sync/interprocess_condition_any.hpp +++ b/include/boost/interprocess/sync/interprocess_condition_any.hpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -118,6 +119,30 @@ class interprocess_condition_any template bool timed_wait(L& lock, const TimePoint &abs_time, Pr pred) { return m_cond.timed_wait(lock, abs_time, pred); } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template + cv_status wait_until(L& lock, const TimePoint &abs_time) + { return this->timed_wait(lock, abs_time) ? cv_status::no_timeout : cv_status::timeout; } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template + bool wait_until(L& lock, const TimePoint &abs_time, Pr pred) + { return this->timed_wait(lock, abs_time, pred); } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface and uses relative timeouts. + template + cv_status wait_for(L& lock, const Duration &dur) + { return this->wait_until(lock, ipcdetail::duration_to_ustime(dur)); } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface and uses relative timeouts + template + bool wait_for(L& lock, const Duration &dur, Pr pred) + { return this->wait_until(lock, ipcdetail::duration_to_ustime(dur), pred); } }; } //namespace interprocess diff --git a/include/boost/interprocess/sync/interprocess_mutex.hpp b/include/boost/interprocess/sync/interprocess_mutex.hpp index fe34567..4eb1f59 100644 --- a/include/boost/interprocess/sync/interprocess_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_mutex.hpp @@ -139,6 +139,16 @@ class interprocess_mutex template bool timed_lock(const TimePoint &abs_time); + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(ipcdetail::duration_to_ustime(dur)); } + //!Effects: The calling thread releases the exclusive ownership of the mutex. //!Throws: interprocess_exception on error. void unlock(); diff --git a/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp index ac67c9b..6658b0c 100644 --- a/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp @@ -122,6 +122,16 @@ class interprocess_recursive_mutex template bool timed_lock(const TimePoint &abs_time); + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(ipcdetail::duration_to_ustime(dur)); } + //!Effects: The calling thread releases the exclusive ownership of the mutex. //! If the mutex supports recursive locking, the mutex must be unlocked the //! same number of times it is locked. diff --git a/include/boost/interprocess/sync/interprocess_sharable_mutex.hpp b/include/boost/interprocess/sync/interprocess_sharable_mutex.hpp index c9610b7..35950ae 100644 --- a/include/boost/interprocess/sync/interprocess_sharable_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_sharable_mutex.hpp @@ -98,6 +98,16 @@ class interprocess_sharable_mutex template bool timed_lock(const TimePoint &abs_time); + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(ipcdetail::duration_to_ustime(dur)); } + //!Precondition: The thread must have exclusive ownership of the mutex. //!Effects: The calling thread releases the exclusive ownership of the mutex. //!Throws: An exception derived from interprocess_exception on error. @@ -117,6 +127,11 @@ class interprocess_sharable_mutex //! an exception could be thrown. void lock_sharable(); + //!Same as `lock_sharable` but with a std-compatible interface + //! + void lock_shared() + { this->lock_sharable(); } + //!Requires: The calling thread does not own the mutex. //! //!Effects: The calling thread tries to acquire sharable ownership of the mutex @@ -131,6 +146,11 @@ class interprocess_sharable_mutex //! an exception could be thrown. bool try_lock_sharable(); + //!Same as `try_lock_sharable` but with a std-compatible interface + //! + bool try_lock_shared() + { return this->try_lock_sharable(); } + //!Requires: The calling thread does not own the mutex. //! //!Effects: The calling thread tries to acquire sharable ownership of the mutex @@ -145,11 +165,26 @@ class interprocess_sharable_mutex template bool timed_lock_sharable(const TimePoint &abs_time); + //!Same as `timed_lock_sharable`, but this function is modeled after the + //!standard library interface. + template bool try_lock_shared_until(const TimePoint &abs_time) + { return this->timed_lock_sharable(abs_time); } + + //!Same as `timed_lock_sharable`, but this function is modeled after the + //!standard library interface. + template bool try_lock_shared_for(const Duration &dur) + { return this->timed_lock_sharable(ipcdetail::duration_to_ustime(dur)); } + //!Precondition: The thread must have sharable ownership of the mutex. //!Effects: The calling thread releases the sharable ownership of the mutex. //!Throws: An exception derived from interprocess_exception on error. void unlock_sharable(); + //!Same as `unlock_sharable` but with a std-compatible interface + //! + void unlock_shared() + { this->unlock_sharable(); } + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) private: typedef scoped_lock scoped_lock_t; diff --git a/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp b/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp index a9bdb8b..359a28f 100644 --- a/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp @@ -96,6 +96,17 @@ class interprocess_upgradable_mutex template bool timed_lock(const TimePoint &abs_time); + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(ipcdetail::duration_to_ustime(dur)); } + + //!Precondition: The thread must have exclusive ownership of the mutex. //!Effects: The calling thread releases the exclusive ownership of the mutex. //!Throws: An exception derived from interprocess_exception on error. @@ -115,6 +126,11 @@ class interprocess_upgradable_mutex //! an exception could be thrown. void lock_sharable(); + //!Same as `lock_sharable` but with a std-compatible interface + //! + void lock_shared() + { this->lock_sharable(); } + //!Requires: The calling thread does not own the mutex. //! //!Effects: The calling thread tries to acquire sharable ownership of the mutex @@ -129,6 +145,11 @@ class interprocess_upgradable_mutex //! an exception could be thrown. bool try_lock_sharable(); + //!Same as `try_lock_sharable` but with a std-compatible interface + //! + bool try_lock_shared() + { return this->try_lock_sharable(); } + //!Requires: The calling thread does not own the mutex. //! //!Effects: The calling thread tries to acquire sharable ownership of the mutex @@ -143,11 +164,26 @@ class interprocess_upgradable_mutex template bool timed_lock_sharable(const TimePoint &abs_time); + //!Same as `timed_lock_sharable`, but this function is modeled after the + //!standard library interface. + template bool try_lock_shared_until(const TimePoint &abs_time) + { return this->timed_lock_sharable(abs_time); } + + //!Same as `timed_lock_sharable`, but this function is modeled after the + //!standard library interface. + template bool try_lock_shared_for(const Duration &dur) + { return this->timed_lock_sharable(ipcdetail::duration_to_ustime(dur)); } + //!Precondition: The thread must have sharable ownership of the mutex. //!Effects: The calling thread releases the sharable ownership of the mutex. //!Throws: An exception derived from interprocess_exception on error. void unlock_sharable(); + //!Same as `unlock_sharable` but with a std-compatible interface + //! + void unlock_shared() + { this->unlock_sharable(); } + //Upgradable locking //!Requires: The calling thread does not own the mutex. diff --git a/include/boost/interprocess/sync/named_condition.hpp b/include/boost/interprocess/sync/named_condition.hpp index e4a28e5..2e62d0f 100644 --- a/include/boost/interprocess/sync/named_condition.hpp +++ b/include/boost/interprocess/sync/named_condition.hpp @@ -21,6 +21,8 @@ #include #include + +#include #include #include #include @@ -147,6 +149,30 @@ class named_condition template bool timed_wait(L& lock, const TimePoint &abs_time, Pr pred); + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template + cv_status wait_until(L& lock, const TimePoint &abs_time) + { return this->timed_wait(lock, abs_time) ? cv_status::no_timeout : cv_status::timeout; } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template + bool wait_until(L& lock, const TimePoint &abs_time, Pr pred) + { return this->timed_wait(lock, abs_time, pred); } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface and uses relative timeouts. + template + cv_status wait_for(L& lock, const Duration &dur) + { return this->wait_until(lock, ipcdetail::duration_to_ustime(dur)); } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface and uses relative timeouts + template + bool wait_for(L& lock, const Duration &dur, Pr pred) + { return this->wait_until(lock, ipcdetail::duration_to_ustime(dur), pred); } + //!Erases a named condition from the system. //!Returns false on error. Never throws. static bool remove(const char *name); diff --git a/include/boost/interprocess/sync/named_condition_any.hpp b/include/boost/interprocess/sync/named_condition_any.hpp index 590be20..174ed9c 100644 --- a/include/boost/interprocess/sync/named_condition_any.hpp +++ b/include/boost/interprocess/sync/named_condition_any.hpp @@ -21,6 +21,8 @@ #include #include + +#include #include #include #include @@ -163,6 +165,30 @@ class named_condition_any bool timed_wait(L& lock, const TimePoint &abs_time, Pr pred) { return m_cond.timed_wait(lock, abs_time, pred); } + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template + cv_status wait_until(L& lock, const TimePoint &abs_time) + { return this->timed_wait(lock, abs_time) ? cv_status::no_timeout : cv_status::timeout; } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template + bool wait_until(L& lock, const TimePoint &abs_time, Pr pred) + { return this->timed_wait(lock, abs_time, pred); } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface and uses relative timeouts. + template + cv_status wait_for(L& lock, const Duration &dur) + { return this->wait_until(lock, ipcdetail::duration_to_ustime(dur)); } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface and uses relative timeouts + template + bool wait_for(L& lock, const Duration &dur, Pr pred) + { return this->wait_until(lock, ipcdetail::duration_to_ustime(dur), pred); } + //!Erases a named condition from the system. //!Returns false on error. Never throws. static bool remove(const char *name) diff --git a/include/boost/interprocess/sync/named_mutex.hpp b/include/boost/interprocess/sync/named_mutex.hpp index 9c0d77d..89c5030 100644 --- a/include/boost/interprocess/sync/named_mutex.hpp +++ b/include/boost/interprocess/sync/named_mutex.hpp @@ -151,6 +151,16 @@ class named_mutex template bool timed_lock(const TimePoint &abs_time); + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(ipcdetail::duration_to_ustime(dur)); } + //!Erases a named mutex from the system. //!Returns false on error. Never throws. static bool remove(const char *name); diff --git a/include/boost/interprocess/sync/named_recursive_mutex.hpp b/include/boost/interprocess/sync/named_recursive_mutex.hpp index ecffb2b..051dc53 100644 --- a/include/boost/interprocess/sync/named_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/named_recursive_mutex.hpp @@ -137,6 +137,16 @@ class named_recursive_mutex template bool timed_lock(const TimePoint &abs_time); + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(ipcdetail::duration_to_ustime(dur)); } + //!Erases a named recursive mutex //!from the system static bool remove(const char *name); diff --git a/include/boost/interprocess/sync/named_sharable_mutex.hpp b/include/boost/interprocess/sync/named_sharable_mutex.hpp index 7c569df..0d65738 100644 --- a/include/boost/interprocess/sync/named_sharable_mutex.hpp +++ b/include/boost/interprocess/sync/named_sharable_mutex.hpp @@ -151,6 +151,16 @@ class named_sharable_mutex template bool timed_lock(const TimePoint &abs_time); + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(ipcdetail::duration_to_ustime(dur)); } + //!Precondition: The thread must have exclusive ownership of the mutex. //!Effects: The calling thread releases the exclusive ownership of the mutex. //!Throws: An exception derived from interprocess_exception on error. @@ -170,6 +180,11 @@ class named_sharable_mutex //! an exception could be thrown void lock_sharable(); + //!Same as `lock_sharable` but with a std-compatible interface + //! + void lock_shared() + { this->lock_sharable(); } + //!Requires: The calling thread does not own the mutex. //! //!Effects: The calling thread tries to acquire sharable ownership of the mutex @@ -184,6 +199,11 @@ class named_sharable_mutex //! an exception could be thrown bool try_lock_sharable(); + //!Same as `try_lock_sharable` but with a std-compatible interface + //! + bool try_lock_shared() + { return this->try_lock_sharable(); } + //!Requires: The calling thread does not own the mutex. //! //!Effects: The calling thread tries to acquire sharable ownership of the mutex @@ -198,11 +218,26 @@ class named_sharable_mutex template bool timed_lock_sharable(const TimePoint &abs_time); + //!Same as `timed_lock_sharable`, but this function is modeled after the + //!standard library interface. + template bool try_lock_shared_until(const TimePoint &abs_time) + { return this->timed_lock_sharable(abs_time); } + + //!Same as `timed_lock_sharable`, but this function is modeled after the + //!standard library interface. + template bool try_lock_shared_for(const Duration &dur) + { return this->timed_lock_sharable(ipcdetail::duration_to_ustime(dur)); } + //!Precondition: The thread must have sharable ownership of the mutex. //!Effects: The calling thread releases the sharable ownership of the mutex. //!Throws: An exception derived from interprocess_exception on error. void unlock_sharable(); + //!Same as `unlock_sharable` but with a std-compatible interface + //! + void unlock_shared() + { this->unlock_sharable(); } + //!Erases a named sharable mutex from the system. //!Returns false on error. Never throws. static bool remove(const char *name); diff --git a/include/boost/interprocess/sync/named_upgradable_mutex.hpp b/include/boost/interprocess/sync/named_upgradable_mutex.hpp index 6af01bb..42cb031 100644 --- a/include/boost/interprocess/sync/named_upgradable_mutex.hpp +++ b/include/boost/interprocess/sync/named_upgradable_mutex.hpp @@ -152,6 +152,16 @@ class named_upgradable_mutex template bool timed_lock(const TimePoint &abs_time); + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(ipcdetail::duration_to_ustime(dur)); } + //!Precondition: The thread must have exclusive ownership of the mutex. //!Effects: The calling thread releases the exclusive ownership of the mutex. //!Throws: An exception derived from interprocess_exception on error. @@ -171,6 +181,11 @@ class named_upgradable_mutex //! an exception could be thrown void lock_sharable(); + //!Same as `lock_sharable` but with a std-compatible interface + //! + void lock_shared() + { this->lock_sharable(); } + //!Requires: The calling thread does not own the mutex. //! //!Effects: The calling thread tries to acquire sharable ownership of the mutex @@ -185,6 +200,11 @@ class named_upgradable_mutex //! an exception could be thrown bool try_lock_sharable(); + //!Same as `try_lock_sharable` but with a std-compatible interface + //! + bool try_lock_shared() + { return this->try_lock_sharable(); } + //!Requires: The calling thread does not own the mutex. //! //!Effects: The calling thread tries to acquire sharable ownership of the mutex @@ -199,11 +219,26 @@ class named_upgradable_mutex template bool timed_lock_sharable(const TimePoint &abs_time); + //!Same as `timed_lock_sharable`, but this function is modeled after the + //!standard library interface. + template bool try_lock_shared_until(const TimePoint &abs_time) + { return this->timed_lock_sharable(abs_time); } + + //!Same as `timed_lock_sharable`, but this function is modeled after the + //!standard library interface. + template bool try_lock_shared_for(const Duration &dur) + { return this->timed_lock_sharable(ipcdetail::duration_to_ustime(dur)); } + //!Precondition: The thread must have sharable ownership of the mutex. //!Effects: The calling thread releases the sharable ownership of the mutex. //!Throws: An exception derived from interprocess_exception on error. void unlock_sharable(); + //!Same as `unlock_sharable` but with a std-compatible interface + //! + void unlock_shared() + { this->unlock_sharable(); } + //Upgradable locking //!Requires: The calling thread does not own the mutex. diff --git a/include/boost/interprocess/sync/null_mutex.hpp b/include/boost/interprocess/sync/null_mutex.hpp index 72eae51..cf12c9e 100644 --- a/include/boost/interprocess/sync/null_mutex.hpp +++ b/include/boost/interprocess/sync/null_mutex.hpp @@ -61,6 +61,18 @@ class null_mutex bool timed_lock(const TimePoint &) { return true; } + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template + bool try_lock_until(const TimePoint &) + { return true; } + + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template + bool try_lock_for(const Duration &) + { return true; } + //!Simulates a mutex unlock() operation. //!Empty function. void unlock(){} @@ -69,11 +81,21 @@ class null_mutex //!Empty function. void lock_sharable(){} + //!Same as `lock_sharable` but with a std-compatible interface + //! + void lock_shared() + { this->lock_sharable(); } + //!Simulates a mutex try_lock_sharable() operation. //!Equivalent to "return true;" bool try_lock_sharable() { return true; } + //!Same as `try_lock_sharable` but with a std-compatible interface + //! + bool try_lock_shared() + { return this->try_lock_sharable(); } + //!Simulates a mutex timed_lock_sharable() operation. //!Equivalent to "return true;" template @@ -84,6 +106,11 @@ class null_mutex //!Empty function. void unlock_sharable(){} + //!Same as `unlock_sharable` but with a std-compatible interface + //! + void unlock_shared() + { this->unlock_sharable(); } + //!Simulates a mutex lock_upgradable() operation. //!Empty function. void lock_upgradable(){} diff --git a/include/boost/interprocess/sync/posix/condition.hpp b/include/boost/interprocess/sync/posix/condition.hpp index 9ab47dd..f151a5b 100644 --- a/include/boost/interprocess/sync/posix/condition.hpp +++ b/include/boost/interprocess/sync/posix/condition.hpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -117,6 +118,25 @@ class posix_condition return true; } + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template + cv_status wait_until(L& lock, const TimePoint &abs_time) + { return this->timed_wait(lock, abs_time) ? cv_status::no_timeout : cv_status::timeout; } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template + bool wait_until(L& lock, const TimePoint &abs_time, Pr pred) + { return this->timed_wait(lock, abs_time, pred); } + + template + cv_status wait_for(L& lock, const Duration &dur) + { return this->wait_until(lock, duration_to_ustime(dur)) ? cv_status::no_timeout : cv_status::timeout; } + + template + bool wait_for(L& lock, const Duration &dur, Pr pred) + { return this->wait_until(lock, duration_to_ustime(dur), pred); } void do_wait(posix_mutex &mut); diff --git a/include/boost/interprocess/sync/posix/mutex.hpp b/include/boost/interprocess/sync/posix/mutex.hpp index f679181..174a871 100644 --- a/include/boost/interprocess/sync/posix/mutex.hpp +++ b/include/boost/interprocess/sync/posix/mutex.hpp @@ -71,6 +71,13 @@ class posix_mutex void lock(); bool try_lock(); template bool timed_lock(const TimePoint &abs_time); + + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(duration_to_ustime(dur)); } + void unlock(); friend class posix_condition; diff --git a/include/boost/interprocess/sync/posix/named_mutex.hpp b/include/boost/interprocess/sync/posix/named_mutex.hpp index f9e7e4f..32f2120 100644 --- a/include/boost/interprocess/sync/posix/named_mutex.hpp +++ b/include/boost/interprocess/sync/posix/named_mutex.hpp @@ -56,7 +56,18 @@ class posix_named_mutex void unlock(); void lock(); bool try_lock(); - template bool timed_lock(const TimePoint &abs_time); + + template + bool timed_lock(const TimePoint &abs_time); + + template + bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + template + bool try_lock_for(const Duration &dur) + { return this->timed_lock(duration_to_ustime(dur)); } + static bool remove(const char *name); #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) diff --git a/include/boost/interprocess/sync/posix/timepoint_to_timespec.hpp b/include/boost/interprocess/sync/posix/timepoint_to_timespec.hpp index f9652bd..04918d8 100644 --- a/include/boost/interprocess/sync/posix/timepoint_to_timespec.hpp +++ b/include/boost/interprocess/sync/posix/timepoint_to_timespec.hpp @@ -31,7 +31,7 @@ namespace ipcdetail { template inline timespec timepoint_to_timespec ( const TimePoint &tm - , typename enable_if_ptime::type * = 0) + , typename enable_if_ptime::type * = 0) { typedef typename TimePoint::date_type date_type; typedef typename TimePoint::time_duration_type time_duration_type; @@ -57,7 +57,7 @@ inline timespec timepoint_to_timespec (const ustime &tm) template inline timespec timepoint_to_timespec ( const TimePoint &tm - , typename enable_if_time_point::type * = 0) + , typename enable_if_time_point::type * = 0) { typedef typename TimePoint::duration duration_t; duration_t d(tm.time_since_epoch()); diff --git a/include/boost/interprocess/sync/scoped_lock.hpp b/include/boost/interprocess/sync/scoped_lock.hpp index ecbb240..eb1fb4f 100644 --- a/include/boost/interprocess/sync/scoped_lock.hpp +++ b/include/boost/interprocess/sync/scoped_lock.hpp @@ -316,6 +316,38 @@ class scoped_lock return m_locked; } + //!Effects: If mutex() == 0 or if already locked, throws a lock_exception() + //! exception. Calls try_lock_until(abs_time) on the referenced mutex. + //!Postconditions: owns() == the value returned from mutex()-> timed_lock(abs_time). + //!Notes: The scoped_lock changes from a state of not owning the mutex, to + //! owning the mutex, but only if it can obtain ownership by the specified + //! time. If the mutex_type does not support timed_lock (), this function + //! will fail at compile time if instantiated, but otherwise have no effect.*/ + template + bool try_lock_until(const TimePoint& abs_time) + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->try_lock_until(abs_time); + return m_locked; + } + + //!Effects: If mutex() == 0 or if already locked, throws a lock_exception() + //! exception. Calls try_lock_until(abs_time) on the referenced mutex. + //!Postconditions: owns() == the value returned from mutex()-> timed_lock(abs_time). + //!Notes: The scoped_lock changes from a state of not owning the mutex, to + //! owning the mutex, but only if it can obtain ownership by the specified + //! time. If the mutex_type does not support timed_lock (), this function + //! will fail at compile time if instantiated, but otherwise have no effect.*/ + template + bool try_lock_for(const Duration& dur) + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->try_lock_for(dur); + return m_locked; + } + //!Effects: If mutex() == 0 or if not locked, throws a lock_exception() //! exception. Calls unlock() on the referenced mutex. //!Postconditions: owns() == false. diff --git a/include/boost/interprocess/sync/sharable_lock.hpp b/include/boost/interprocess/sync/sharable_lock.hpp index 89b8550..244073b 100644 --- a/include/boost/interprocess/sync/sharable_lock.hpp +++ b/include/boost/interprocess/sync/sharable_lock.hpp @@ -249,6 +249,46 @@ class sharable_lock return m_locked; } + //!Effects: If mutex() == 0 or already locked, throws a lock_exception() + //! exception. Calls try_lock_shared_until(abs_time) on the referenced mutex. + //!Postconditions: owns() == the value returned from + //! mutex()->timed_lock_sharable(elps_time). + //!Notes: The sharable_lock changes from a state of not owning the mutex, + //! to owning the mutex, but only if it can obtain ownership within the + //! specified time interval. If the mutex_type does not support + //! timed_lock_sharable(), this function will fail at compile time if + //! instantiated, but otherwise have no effect. + //! + //!Note: Similar to timed_lock, but with a std-like interface + template + bool try_lock_until(const TimePoint& abs_time) + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->try_lock_shared_until(abs_time); + return m_locked; + } + + //!Effects: If mutex() == 0 or already locked, throws a lock_exception() + //! exception. Calls try_lock_shared_until(abs_time) on the referenced mutex. + //!Postconditions: owns() == the value returned from + //! mutex()->timed_lock_sharable(elps_time). + //!Notes: The sharable_lock changes from a state of not owning the mutex, + //! to owning the mutex, but only if it can obtain ownership within the + //! specified time interval. If the mutex_type does not support + //! timed_lock_sharable(), this function will fail at compile time if + //! instantiated, but otherwise have no effect. + //! + //!Note: Similar to timed_lock, but with a std-like interface + template + bool try_lock_for(const Duration& dur) + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->try_lock_shared_for(dur); + return m_locked; + } + //!Effects: If mutex() == 0 or not locked, throws a lock_exception() exception. //! Calls unlock_sharable() on the referenced mutex. //!Postconditions: owns() == false. diff --git a/include/boost/interprocess/sync/shm/named_condition.hpp b/include/boost/interprocess/sync/shm/named_condition.hpp index 59d21dc..b240c07 100644 --- a/include/boost/interprocess/sync/shm/named_condition.hpp +++ b/include/boost/interprocess/sync/shm/named_condition.hpp @@ -21,6 +21,8 @@ #include #include + +#include #include #include #include @@ -151,6 +153,30 @@ class shm_named_condition template bool timed_wait(L& lock, const TimePoint &abs_time, Pr pred); + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template + cv_status wait_until(L& lock, const TimePoint &abs_time) + { return this->timed_wait(lock, abs_time) ? cv_status::no_timeout : cv_status::timeout; } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template + bool wait_until(L& lock, const TimePoint &abs_time, Pr pred) + { return this->timed_wait(lock, abs_time, pred); } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface and uses relative timeouts. + template + cv_status wait_for(L& lock, const Duration &dur) + { return this->wait_until(lock, ipcdetail::duration_to_ustime(dur)); } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface and uses relative timeouts + template + bool wait_for(L& lock, const Duration &dur, Pr pred) + { return this->wait_until(lock, ipcdetail::duration_to_ustime(dur), pred); } + //!Erases a named condition from the system. //!Returns false on error. Never throws. static bool remove(const char *name); diff --git a/include/boost/interprocess/sync/shm/named_condition_any.hpp b/include/boost/interprocess/sync/shm/named_condition_any.hpp index 9ef3bde..046943e 100644 --- a/include/boost/interprocess/sync/shm/named_condition_any.hpp +++ b/include/boost/interprocess/sync/shm/named_condition_any.hpp @@ -21,6 +21,8 @@ #include #include + +#include #include #include #include @@ -150,6 +152,30 @@ class shm_named_condition_any bool timed_wait(L& lock, const TimePoint &abs_time, Pr pred) { return this->internal_cond().timed_wait(lock, abs_time, pred); } + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template + cv_status wait_until(L& lock, const TimePoint &abs_time) + { return this->timed_wait(lock, abs_time) ? cv_status::no_timeout : cv_status::timeout; } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template + bool wait_until(L& lock, const TimePoint &abs_time, Pr pred) + { return this->timed_wait(lock, abs_time, pred); } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface and uses relative timeouts. + template + cv_status wait_for(L& lock, const Duration &dur) + { return this->wait_until(lock, ipcdetail::duration_to_ustime(dur)); } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface and uses relative timeouts + template + bool wait_for(L& lock, const Duration &dur, Pr pred) + { return this->wait_until(lock, ipcdetail::duration_to_ustime(dur), pred); } + //!Erases a named condition from the system. //!Returns false on error. Never throws. template diff --git a/include/boost/interprocess/sync/shm/named_mutex.hpp b/include/boost/interprocess/sync/shm/named_mutex.hpp index f350c4c..8ba653b 100644 --- a/include/boost/interprocess/sync/shm/named_mutex.hpp +++ b/include/boost/interprocess/sync/shm/named_mutex.hpp @@ -120,6 +120,12 @@ class shm_named_mutex template bool timed_lock(const TimePoint &abs_time); + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(duration_to_ustime(dur)); } + //!Erases a named mutex from the system. //!Returns false on error. Never throws. static bool remove(const char *name); diff --git a/include/boost/interprocess/sync/shm/named_recursive_mutex.hpp b/include/boost/interprocess/sync/shm/named_recursive_mutex.hpp index 310bf7f..e077ed5 100644 --- a/include/boost/interprocess/sync/shm/named_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/shm/named_recursive_mutex.hpp @@ -115,6 +115,12 @@ class shm_named_recursive_mutex template bool timed_lock(const TimePoint &abs_time); + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(duration_to_ustime(dur)); } + //!Erases a named recursive mutex //!from the system static bool remove(const char *name); diff --git a/include/boost/interprocess/sync/spin/condition.hpp b/include/boost/interprocess/sync/spin/condition.hpp index 26a5160..cf3a159 100644 --- a/include/boost/interprocess/sync/spin/condition.hpp +++ b/include/boost/interprocess/sync/spin/condition.hpp @@ -21,6 +21,8 @@ #include #include + +#include #include #include #include @@ -63,6 +65,24 @@ class spin_condition void notify_all() { this->notify(NOTIFY_ALL); } + template + void wait(L& lock) + { + if (!lock) + throw lock_exception(); + this->do_timed_wait_impl(0, *lock.mutex()); + } + + template + void wait(L& lock, Pr pred) + { + if (!lock) + throw lock_exception(); + + while (!pred()) + this->do_timed_wait_impl(0, *lock.mutex()); + } + template bool timed_wait(L& lock, const TimePoint &abs_time) { @@ -93,23 +113,21 @@ class spin_condition return true; } - template - void wait(L& lock) - { - if (!lock) - throw lock_exception(); - this->do_timed_wait_impl(0, *lock.mutex()); - } + template + cv_status wait_until(L& lock, const TimePoint &abs_time) + { return this->timed_wait(lock, abs_time) ? cv_status::no_timeout : cv_status::timeout; } - template - void wait(L& lock, Pr pred) - { - if (!lock) - throw lock_exception(); + template + bool wait_until(L& lock, const TimePoint &abs_time, Pr pred) + { return this->timed_wait(lock, abs_time, pred); } - while (!pred()) - this->do_timed_wait_impl(0, *lock.mutex()); - } + template + cv_status wait_for(L& lock, const Duration &dur) + { return this->wait_until(lock, duration_to_ustime(dur)); } + + template + bool wait_for(L& lock, const Duration &dur, Pr pred) + { return this->wait_until(lock, duration_to_ustime(dur), pred); } private: diff --git a/include/boost/interprocess/sync/spin/mutex.hpp b/include/boost/interprocess/sync/spin/mutex.hpp index a0e31fb..ce9f87f 100644 --- a/include/boost/interprocess/sync/spin/mutex.hpp +++ b/include/boost/interprocess/sync/spin/mutex.hpp @@ -42,7 +42,15 @@ class spin_mutex void lock(); bool try_lock(); - template bool timed_lock(const TimePoint &abs_time); + template + bool timed_lock(const TimePoint &abs_time); + + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(duration_to_ustime(dur)); } + void unlock(); void take_ownership(){} private: diff --git a/include/boost/interprocess/sync/spin/recursive_mutex.hpp b/include/boost/interprocess/sync/spin/recursive_mutex.hpp index 84a2db3..3a9e94a 100644 --- a/include/boost/interprocess/sync/spin/recursive_mutex.hpp +++ b/include/boost/interprocess/sync/spin/recursive_mutex.hpp @@ -61,7 +61,15 @@ class spin_recursive_mutex void lock(); bool try_lock(); - template bool timed_lock(const TimePoint &abs_time); + template + bool timed_lock(const TimePoint &abs_time); + + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(duration_to_ustime(dur)); } + void unlock(); void take_ownership(); private: diff --git a/include/boost/interprocess/sync/windows/condition.hpp b/include/boost/interprocess/sync/windows/condition.hpp index 16b79ec..e060caf 100644 --- a/include/boost/interprocess/sync/windows/condition.hpp +++ b/include/boost/interprocess/sync/windows/condition.hpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -57,6 +58,15 @@ class winapi_condition void notify_all() { m_condition_data.notify_all(); } + template + void wait(L& lock) + { m_condition_data.wait(lock); } + + template + void wait(L& lock, Pr pred) + { m_condition_data.wait(lock, pred); } + + template bool timed_wait(L& lock, const TimePoint &abs_time) { return m_condition_data.timed_wait(lock, abs_time); } @@ -65,13 +75,21 @@ class winapi_condition bool timed_wait(L& lock, const TimePoint &abs_time, Pr pred) { return m_condition_data.timed_wait(lock, abs_time, pred); } - template - void wait(L& lock) - { m_condition_data.wait(lock); } + template + cv_status wait_until(L& lock, const TimePoint &abs_time) + { return this->timed_wait(lock, abs_time) ? cv_status::no_timeout : cv_status::timeout; } - template - void wait(L& lock, Pr pred) - { m_condition_data.wait(lock, pred); } + template + bool wait_until(L& lock, const TimePoint &abs_time, Pr pred) + { return this->timed_wait(lock, abs_time, pred); } + + template + cv_status wait_for(L& lock, const Duration &dur) + { return this->wait_until(lock, duration_to_ustime(dur)); } + + template + bool wait_for(L& lock, const Duration &dur, Pr pred) + { return this->wait_until(lock, duration_to_ustime(dur), pred); } private: diff --git a/include/boost/interprocess/sync/windows/mutex.hpp b/include/boost/interprocess/sync/windows/mutex.hpp index 43786ba..55c2472 100644 --- a/include/boost/interprocess/sync/windows/mutex.hpp +++ b/include/boost/interprocess/sync/windows/mutex.hpp @@ -44,6 +44,13 @@ class winapi_mutex void lock(); bool try_lock(); template bool timed_lock(const TimePoint &abs_time); + + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(duration_to_ustime(dur)); } + void unlock(); void take_ownership(){}; diff --git a/include/boost/interprocess/sync/windows/named_condition.hpp b/include/boost/interprocess/sync/windows/named_condition.hpp index ad10367..2f9354c 100644 --- a/include/boost/interprocess/sync/windows/named_condition.hpp +++ b/include/boost/interprocess/sync/windows/named_condition.hpp @@ -21,6 +21,8 @@ #include #include + +#include #include namespace boost { diff --git a/include/boost/interprocess/sync/windows/named_condition_any.hpp b/include/boost/interprocess/sync/windows/named_condition_any.hpp index 2e13765..9271ce2 100644 --- a/include/boost/interprocess/sync/windows/named_condition_any.hpp +++ b/include/boost/interprocess/sync/windows/named_condition_any.hpp @@ -21,6 +21,8 @@ #include #include + +#include #include #include #include @@ -156,6 +158,22 @@ class winapi_named_condition_any void wait(L& lock, Pr pred) { m_condition_data.wait(lock, pred); } + template + cv_status wait_until(L& lock, const TimePoint &abs_time) + { return this->timed_wait(lock, abs_time) ? cv_status::no_timeout : cv_status::timeout; } + + template + bool wait_until(L& lock, const TimePoint &abs_time, Pr pred) + { return this->timed_wait(lock, abs_time, pred); } + + template + cv_status wait_for(L& lock, const Duration &dur) + { return this->wait_until(lock, ipcdetail::duration_to_ustime(dur)); } + + template + bool wait_for(L& lock, const Duration &dur, Pr pred) + { return this->wait_until(lock, ipcdetail::duration_to_ustime(dur), pred); } + static bool remove(const char *name) { return windows_named_sync::remove(name); } diff --git a/include/boost/interprocess/sync/windows/named_mutex.hpp b/include/boost/interprocess/sync/windows/named_mutex.hpp index 78e4301..98f5b9c 100644 --- a/include/boost/interprocess/sync/windows/named_mutex.hpp +++ b/include/boost/interprocess/sync/windows/named_mutex.hpp @@ -66,6 +66,12 @@ class winapi_named_mutex bool try_lock(); template bool timed_lock(const TimePoint &abs_time); + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(duration_to_ustime(dur)); } + static bool remove(const char *name); static bool remove(const wchar_t *name); diff --git a/test/condition_test_template.hpp b/test/condition_test_template.hpp index 825ac3e..de3929f 100644 --- a/test/condition_test_template.hpp +++ b/test/condition_test_template.hpp @@ -87,54 +87,7 @@ struct cond_predicate int _val; }; -template -void condition_test_waits(condition_test_data* data) -{ - boost::interprocess::scoped_lock - lock(data->mutex); - BOOST_INTERPROCESS_CHECK(lock ? true : false); - // Test wait. - while (data->notified != 1) - data->condition.wait(lock); - BOOST_INTERPROCESS_CHECK(lock ? true : false); - BOOST_INTERPROCESS_CHECK(data->notified == 1); - data->awoken++; - data->condition.notify_one(); - - // Test predicate wait. - data->condition.wait(lock, cond_predicate(data->notified, 2)); - BOOST_INTERPROCESS_CHECK(lock ? true : false); - BOOST_INTERPROCESS_CHECK(data->notified == 2); - data->awoken++; - data->condition.notify_one(); - - // Test timed_wait - while (data->notified != 3) - data->condition.timed_wait(lock, ptime_delay(5)); - BOOST_INTERPROCESS_CHECK(lock ? true : false); - BOOST_INTERPROCESS_CHECK(data->notified == 3); - data->awoken++; - data->condition.notify_one(); - - // Test predicate timed_wait. - cond_predicate pred(data->notified, 4); - bool ret = data->condition.timed_wait(lock, boost_systemclock_delay(5), pred); - BOOST_INTERPROCESS_CHECK(ret);(void)ret; - BOOST_INTERPROCESS_CHECK(lock ? true : false); - BOOST_INTERPROCESS_CHECK(pred()); - BOOST_INTERPROCESS_CHECK(data->notified == 4); - data->awoken++; - data->condition.notify_one(); - - // Test timed_wait - while (data->notified != 5) - data->condition.timed_wait(lock, std_systemclock_delay(5)); - BOOST_INTERPROCESS_CHECK(lock ? true : false); - BOOST_INTERPROCESS_CHECK(data->notified == 5); - data->awoken++; - data->condition.notify_one(); -} template void do_test_condition_notify_one() @@ -185,6 +138,141 @@ void do_test_condition_notify_all() BOOST_INTERPROCESS_CHECK(data.awoken == NUMTHREADS); } +template +void do_test_condition_waits_step( condition_test_data &data + , boost::interprocess::scoped_lock &lock + , int awoken) +{ + boost::interprocess::ipcdetail::thread_sleep(1000); + data.notified++; + data.condition.notify_one(); + while (data.awoken != awoken) + data.condition.wait(lock); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data.awoken == awoken); +} + +template +void condition_test_waits(condition_test_data* data) +{ + boost::interprocess::scoped_lock + lock(data->mutex); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + + // Test wait. + while (data->notified != 1) + data->condition.wait(lock); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data->notified == 1); + data->awoken++; + data->condition.notify_one(); + + // Test predicate wait. + data->condition.wait(lock, cond_predicate(data->notified, 2)); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data->notified == 2); + data->awoken++; + data->condition.notify_one(); + + // Test timed_wait + while (data->notified != 3) + data->condition.timed_wait(lock, ptime_delay(5)); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data->notified == 3); + data->awoken++; + data->condition.notify_one(); + + // Test predicate timed_wait. + { + bool ret = data->condition.timed_wait(lock, boost_systemclock_delay(5), cond_predicate (data->notified, 4)); + BOOST_INTERPROCESS_CHECK(ret);(void)ret; + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data->notified == 4); + data->awoken++; + data->condition.notify_one(); + } + + // Test timed_wait + while (data->notified != 5) + data->condition.timed_wait(lock, std_systemclock_delay(5)); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data->notified == 5); + data->awoken++; + data->condition.notify_one(); + + // Test wait_until + while (data->notified != 6) + data->condition.wait_until(lock, ptime_delay(5)); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data->notified == 6); + data->awoken++; + data->condition.notify_one(); + + // Test predicate wait_until. + { + bool ret = data->condition.wait_until(lock, boost_systemclock_delay(5), cond_predicate (data->notified, 7)); + BOOST_INTERPROCESS_CHECK(ret);(void)ret; + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data->notified == 7); + data->awoken++; + data->condition.notify_one(); + } + + // Test wait_for + while (data->notified != 8) + data->condition.wait_for(lock, ptime_seconds(5)); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data->notified == 8); + data->awoken++; + data->condition.notify_one(); + + // Test predicate wait_for. + { + bool ret = data->condition.wait_for(lock, ptime_seconds(5), cond_predicate (data->notified, 9)); + BOOST_INTERPROCESS_CHECK(ret);(void)ret; + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data->notified == 9); + data->awoken++; + data->condition.notify_one(); + } + + // Test wait_for + while (data->notified != 10) + data->condition.wait_for(lock, boost_systemclock_seconds(5)); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data->notified == 10); + data->awoken++; + data->condition.notify_one(); + + // Test predicate wait_for. + { + bool ret = data->condition.wait_for(lock, boost_systemclock_seconds(5), cond_predicate (data->notified, 11)); + BOOST_INTERPROCESS_CHECK(ret);(void)ret; + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data->notified == 11); + data->awoken++; + data->condition.notify_one(); + } + + // Test wait_for + while (data->notified != 12) + data->condition.wait_for(lock, std_systemclock_seconds(5)); + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data->notified == 12); + data->awoken++; + data->condition.notify_one(); + + // Test predicate wait_for. + { + bool ret = data->condition.wait_for(lock, std_systemclock_seconds(5), cond_predicate (data->notified, 13)); + BOOST_INTERPROCESS_CHECK(ret);(void)ret; + BOOST_INTERPROCESS_CHECK(lock ? true : false); + BOOST_INTERPROCESS_CHECK(data->notified == 13); + data->awoken++; + data->condition.notify_one(); + } +} + template void do_test_condition_waits() { @@ -197,50 +285,14 @@ void do_test_condition_waits() lock(data.mutex); BOOST_INTERPROCESS_CHECK(lock ? true : false); - boost::interprocess::ipcdetail::thread_sleep(1000); - data.notified++; - data.condition.notify_one(); - while (data.awoken != 1) - data.condition.wait(lock); - BOOST_INTERPROCESS_CHECK(lock ? true : false); - BOOST_INTERPROCESS_CHECK(data.awoken == 1); - - boost::interprocess::ipcdetail::thread_sleep(1000); - data.notified++; - data.condition.notify_one(); - while (data.awoken != 2) - data.condition.wait(lock); - BOOST_INTERPROCESS_CHECK(lock ? true : false); - BOOST_INTERPROCESS_CHECK(data.awoken == 2); - - boost::interprocess::ipcdetail::thread_sleep(1000); - data.notified++; - data.condition.notify_one(); - while (data.awoken != 3) - data.condition.wait(lock); - BOOST_INTERPROCESS_CHECK(lock ? true : false); - BOOST_INTERPROCESS_CHECK(data.awoken == 3); - - boost::interprocess::ipcdetail::thread_sleep(1000); - data.notified++; - data.condition.notify_one(); - while (data.awoken != 4) - data.condition.wait(lock); - BOOST_INTERPROCESS_CHECK(lock ? true : false); - BOOST_INTERPROCESS_CHECK(data.awoken == 4); - - boost::interprocess::ipcdetail::thread_sleep(1000); - data.notified++; - data.condition.notify_one(); - while (data.awoken != 5) - data.condition.wait(lock); - BOOST_INTERPROCESS_CHECK(lock ? true : false); - BOOST_INTERPROCESS_CHECK(data.awoken == 5); + for(int i = 1; i <= 13; ++i) + do_test_condition_waits_step(data, lock, i); } boost::interprocess::ipcdetail::thread_join(thread); - BOOST_INTERPROCESS_CHECK(data.awoken == 5); + BOOST_INTERPROCESS_CHECK(data.awoken == 13); } + /* //Message queue simulation test template diff --git a/test/file_lock_test.cpp b/test/file_lock_test.cpp index 800f98b..4c53bd6 100644 --- a/test/file_lock_test.cpp +++ b/test/file_lock_test.cpp @@ -70,7 +70,7 @@ int main () mapping.swap(move_assign); } - //test::test_all_lock(); + test::test_all_lock(); //test::test_all_mutex(); //test::test_all_sharable_mutex(); std::remove(get_filename().c_str()); diff --git a/test/mutex_test_template.hpp b/test/mutex_test_template.hpp index 7732c66..6741db3 100644 --- a/test/mutex_test_template.hpp +++ b/test/mutex_test_template.hpp @@ -224,13 +224,32 @@ void try_lock_and_sleep(void *arg, M &sm) } } +enum ETimedLockFlags +{ + TimedLock = 0, + TryLockUntil = 1, + TryLockFor = 2, + ETimedLockFlagsMax +}; + template void timed_lock_and_sleep(void *arg, M &sm) { data *pdata = static_cast*>(arg); boost::interprocess::scoped_lock l (sm, boost::interprocess::defer_lock); - if (l.timed_lock(std_systemclock_delay(pdata->m_secs))){ + bool r = false; + if(pdata->m_flags == (int)TimedLock){ + r = l.timed_lock(std_systemclock_delay(pdata->m_secs)); + } + else if (pdata->m_flags == (int)TryLockUntil) { + r = l.try_lock_until(ptime_delay(pdata->m_secs)); + } + else if (pdata->m_flags == (int)TryLockFor) { + r = l.try_lock_for(boost_systemclock_seconds(pdata->m_secs)); + } + + if (r){ boost::interprocess::ipcdetail::thread_sleep((1000*2*BaseSeconds)); ++shared_val; pdata->m_value = shared_val; @@ -336,33 +355,35 @@ void test_mutex_try_lock() template void test_mutex_timed_lock() - { - shared_val = 0; + for (int flag = 0; flag != (int)ETimedLockFlagsMax; ++flag) + { + shared_val = 0; - M mtx, m2; + M mtx, m2; - data d1(1, 2*BaseSeconds); - data d2(2, 2*BaseSeconds); + data d1(1, 2*BaseSeconds, flag); + data d2(2, 2*BaseSeconds, flag); - // Locker one launches, holds the lock for 2*BaseSeconds seconds. - boost::interprocess::ipcdetail::OS_thread_t tm1; - boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter(&timed_lock_and_sleep, &d1, mtx)); + // Locker one launches, holds the lock for 2*BaseSeconds seconds. + boost::interprocess::ipcdetail::OS_thread_t tm1; + boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter(&timed_lock_and_sleep, &d1, mtx)); - //Wait 1*BaseSeconds - boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); + //Wait 1*BaseSeconds + boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); - // Locker two launches, holds the lock for 2*BaseSeconds seconds. - boost::interprocess::ipcdetail::OS_thread_t tm2; - boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter(&timed_lock_and_sleep, &d2, mtx)); + // Locker two launches, holds the lock for 2*BaseSeconds seconds. + boost::interprocess::ipcdetail::OS_thread_t tm2; + boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter(&timed_lock_and_sleep, &d2, mtx)); - //Wait completion - boost::interprocess::ipcdetail::thread_join(tm1); - boost::interprocess::ipcdetail::thread_join(tm2); + //Wait completion + boost::interprocess::ipcdetail::thread_join(tm1); + boost::interprocess::ipcdetail::thread_join(tm2); - //Both should succeed locking - BOOST_INTERPROCESS_CHECK(d1.m_value == 1); - BOOST_INTERPROCESS_CHECK(d2.m_value == 2); + //Both should succeed locking + BOOST_INTERPROCESS_CHECK(d1.m_value == 1); + BOOST_INTERPROCESS_CHECK(d2.m_value == 2); + } } template diff --git a/test/named_condition_test_helpers.hpp b/test/named_condition_test_helpers.hpp index 952a972..e368592 100644 --- a/test/named_condition_test_helpers.hpp +++ b/test/named_condition_test_helpers.hpp @@ -100,6 +100,20 @@ class named_condition_test_wrapper return NamedCondition::timed_wait(internal_lock, abs_time, pred); } + template + cv_status wait_until(L& lock, const TimePoint &abs_time) + { + ipcdetail::internal_mutex_lock internal_lock(lock); + return NamedCondition::wait_until(internal_lock, abs_time); + } + + template + bool wait_until(L& lock, const TimePoint &abs_time, Pr pred) + { + ipcdetail::internal_mutex_lock internal_lock(lock); + return NamedCondition::wait_until(internal_lock, abs_time, pred); + } + static int count; }; diff --git a/test/named_semaphore_test.cpp b/test/named_semaphore_test.cpp index 1a9586a..5e4d3b3 100644 --- a/test/named_semaphore_test.cpp +++ b/test/named_semaphore_test.cpp @@ -21,6 +21,8 @@ #include #endif +#include + using namespace boost::interprocess; static const std::size_t RecSemCount = 100; @@ -61,6 +63,12 @@ class lock_test_wrapper bool timed_lock(const TimePoint &pt) { return this->timed_wait(pt); } + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(boost::interprocess::ipcdetail::duration_to_ustime(dur)); } + void unlock() { this->post(); } }; diff --git a/test/semaphore_test.cpp b/test/semaphore_test.cpp index 8712dcb..4f4c349 100644 --- a/test/semaphore_test.cpp +++ b/test/semaphore_test.cpp @@ -37,6 +37,12 @@ class semaphore_test_wrapper bool timed_lock(const TimePoint &pt) { return this->timed_wait(pt); } + template bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + template bool try_lock_for(const Duration &dur) + { return this->timed_lock(boost::interprocess::ipcdetail::duration_to_ustime(dur)); } + void unlock() { this->post(); } diff --git a/test/sharable_mutex_test_template.hpp b/test/sharable_mutex_test_template.hpp index d4bee37..fb437b0 100644 --- a/test/sharable_mutex_test_template.hpp +++ b/test/sharable_mutex_test_template.hpp @@ -81,34 +81,6 @@ void try_shared(void *arg, SM &sm) } } -template -void timed_exclusive(void *arg, SM &sm) -{ - data *pdata = static_cast*>(arg); - boost::posix_time::ptime pt(ptime_delay(pdata->m_secs)); - boost::interprocess::scoped_lock - l (sm, boost::interprocess::defer_lock); - if (l.timed_lock(pt)){ - boost::interprocess::ipcdetail::thread_sleep((1000*3*BaseSeconds)); - shared_val += 10; - pdata->m_value = shared_val; - } -} - -template -void timed_shared(void *arg, SM &sm) -{ - data *pdata = static_cast*>(arg); - boost::interprocess::sharable_lock - l(sm, boost::interprocess::defer_lock); - if (l.timed_lock(boost_systemclock_delay(pdata->m_secs))){ - if(pdata->m_secs){ - boost::interprocess::ipcdetail::thread_sleep((1000*pdata->m_secs*BaseSeconds)); - } - pdata->m_value = shared_val; - } -} - template void test_plain_sharable_mutex() { @@ -223,50 +195,104 @@ void test_try_sharable_mutex() BOOST_INTERPROCESS_CHECK(e2.m_value == -1); // Try would return w/o waiting } +template +void timed_exclusive(void *arg, SM &sm) +{ + data *pdata = static_cast*>(arg); + boost::interprocess::scoped_lock + l (sm, boost::interprocess::defer_lock); + + bool r = false; + if(pdata->m_flags == (int)TimedLock){ + r = l.timed_lock(std_systemclock_delay(pdata->m_secs)); + } + else if (pdata->m_flags == (int)TryLockUntil) { + r = l.try_lock_until(ptime_delay(pdata->m_secs)); + } + else if (pdata->m_flags == (int)TryLockFor) { + r = l.try_lock_for(boost_systemclock_seconds(pdata->m_secs)); + } + + if (r){ + boost::interprocess::ipcdetail::thread_sleep((1000*3*BaseSeconds)); + shared_val += 10; + pdata->m_value = shared_val; + } +} + +template +void timed_shared(void *arg, SM &sm) +{ + data *pdata = static_cast*>(arg); + boost::interprocess::sharable_lock + l(sm, boost::interprocess::defer_lock); + + bool r = false; + if(pdata->m_flags == (int)TimedLock){ + r = l.timed_lock(std_systemclock_delay(pdata->m_secs)); + } + else if (pdata->m_flags == (int)TryLockUntil) { + r = l.try_lock_until(ptime_delay(pdata->m_secs)); + } + else if (pdata->m_flags == (int)TryLockFor) { + r = l.try_lock_for(boost_systemclock_seconds(pdata->m_secs)); + } + + if (r){ + if(pdata->m_secs){ + boost::interprocess::ipcdetail::thread_sleep((1000*pdata->m_secs*BaseSeconds)); + } + pdata->m_value = shared_val; + } +} + template void test_timed_sharable_mutex() { - SM mtx; - data s1(1,1*BaseSeconds); - data s2(2,3*BaseSeconds); - data e1(3,3*BaseSeconds); - data e2(4,1*BaseSeconds); + for (int flag = 0; flag != (int)ETimedLockFlagsMax; ++flag) + { + SM mtx; + data s1(1,1*BaseSeconds, flag); + data s2(2,3*BaseSeconds, flag); + data e1(3,3*BaseSeconds, flag); + data e2(4,1*BaseSeconds, flag); - // We begin with some specialized tests for "timed" behavior + // We begin with some specialized tests for "timed" behavior - shared_val = 0; + shared_val = 0; - // Writer one will hold the lock for 3*BaseSeconds seconds. - boost::interprocess::ipcdetail::OS_thread_t tw1; - boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter(timed_exclusive,&e1,mtx)); + // Writer one will hold the lock for 3*BaseSeconds seconds. + boost::interprocess::ipcdetail::OS_thread_t tw1; + boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter(timed_exclusive,&e1,mtx)); - boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); - // Writer two will "clearly" try for the lock after the readers - // have tried for it. Writer will wait up 1*BaseSeconds seconds for the lock. - // This write will fail. - boost::interprocess::ipcdetail::OS_thread_t tw2; - boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter(timed_exclusive,&e2,mtx)); + boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); + // Writer two will "clearly" try for the lock after the readers + // have tried for it. Writer will wait up 1*BaseSeconds seconds for the lock. + // This write will fail. + boost::interprocess::ipcdetail::OS_thread_t tw2; + boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter(timed_exclusive,&e2,mtx)); - // Readers one and two will "clearly" try for the lock after writer - // one already holds it. 1st reader will wait 1*BaseSeconds seconds, and will fail - // to get the lock. 2nd reader will wait 3*BaseSeconds seconds, and will get - // the lock. + // Readers one and two will "clearly" try for the lock after writer + // one already holds it. 1st reader will wait 1*BaseSeconds seconds, and will fail + // to get the lock. 2nd reader will wait 3*BaseSeconds seconds, and will get + // the lock. - boost::interprocess::ipcdetail::OS_thread_t thr1; - boost::interprocess::ipcdetail::thread_launch(thr1, thread_adapter(timed_shared,&s1,mtx)); + boost::interprocess::ipcdetail::OS_thread_t thr1; + boost::interprocess::ipcdetail::thread_launch(thr1, thread_adapter(timed_shared,&s1,mtx)); - boost::interprocess::ipcdetail::OS_thread_t thr2; - boost::interprocess::ipcdetail::thread_launch(thr2, thread_adapter(timed_shared,&s2,mtx)); + boost::interprocess::ipcdetail::OS_thread_t thr2; + boost::interprocess::ipcdetail::thread_launch(thr2, thread_adapter(timed_shared,&s2,mtx)); - boost::interprocess::ipcdetail::thread_join(tw1); - boost::interprocess::ipcdetail::thread_join(thr1); - boost::interprocess::ipcdetail::thread_join(thr2); - boost::interprocess::ipcdetail::thread_join(tw2); + boost::interprocess::ipcdetail::thread_join(tw1); + boost::interprocess::ipcdetail::thread_join(thr1); + boost::interprocess::ipcdetail::thread_join(thr2); + boost::interprocess::ipcdetail::thread_join(tw2); - BOOST_INTERPROCESS_CHECK(e1.m_value == 10); - BOOST_INTERPROCESS_CHECK(s1.m_value == -1); - BOOST_INTERPROCESS_CHECK(s2.m_value == 10); - BOOST_INTERPROCESS_CHECK(e2.m_value == -1); + BOOST_INTERPROCESS_CHECK(e1.m_value == 10); + BOOST_INTERPROCESS_CHECK(s1.m_value == -1); + BOOST_INTERPROCESS_CHECK(s2.m_value == 10); + BOOST_INTERPROCESS_CHECK(e2.m_value == -1); + } } template diff --git a/test/util.hpp b/test/util.hpp index 091a70a..15faa36 100644 --- a/test/util.hpp +++ b/test/util.hpp @@ -50,19 +50,31 @@ inline boost::posix_time::ptime ptime_delay(int secs, int msecs=0, int nsecs = 0 return cur += boost::posix_time::time_duration(0, 0, secs, count); } +inline boost::posix_time::time_duration ptime_seconds(int secs) +{ return boost::posix_time::time_duration(0, 0, secs); } + inline boost::chrono::system_clock::time_point boost_systemclock_delay(int secs) { return boost::chrono::system_clock::now() + boost::chrono::seconds(secs); } +inline boost::chrono::seconds boost_systemclock_seconds(int secs) +{ return boost::chrono::seconds(secs); } + #if !defined(BOOST_NO_CXX11_HDR_CHRONO) //Use std chrono if available inline std::chrono::system_clock::time_point std_systemclock_delay(int secs) { return std::chrono::system_clock::now() + std::chrono::seconds(secs); } +inline std::chrono::seconds std_systemclock_seconds(int secs) +{ return std::chrono::seconds(secs); } + #else //Otherwise use boost chrono inline boost::chrono::system_clock::time_point std_systemclock_delay(int secs) { return boost_systemclock_delay(secs); } +inline boost::chrono::seconds std_systemclock_seconds(int secs) +{ return boost::chrono::seconds(secs); } + #endif @@ -83,13 +95,14 @@ class thread_adapter template struct data { - explicit data(int id, int secs=0) - : m_id(id), m_value(-1), m_secs(secs), m_error(no_error) + explicit data(int id, int secs=0, int flags = 0) + : m_id(id), m_value(-1), m_secs(secs), m_error(no_error), m_flags(flags) {} int m_id; int m_value; int m_secs; error_code_t m_error; + int m_flags; }; int shared_val = 0;