libstdc++
unique_lock.h
Go to the documentation of this file.
00001 // std::unique_lock implementation -*- C++ -*-
00002 
00003 // Copyright (C) 2008-2019 Free Software Foundation, Inc.
00004 //
00005 // This file is part of the GNU ISO C++ Library.  This library is free
00006 // software; you can redistribute it and/or modify it under the
00007 // terms of the GNU General Public License as published by the
00008 // Free Software Foundation; either version 3, or (at your option)
00009 // any later version.
00010 
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 
00016 // Under Section 7 of GPL version 3, you are granted additional
00017 // permissions described in the GCC Runtime Library Exception, version
00018 // 3.1, as published by the Free Software Foundation.
00019 
00020 // You should have received a copy of the GNU General Public License and
00021 // a copy of the GCC Runtime Library Exception along with this program;
00022 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
00023 // <http://www.gnu.org/licenses/>.
00024 
00025 /** @file bits/unique_lock.h
00026  *  This is an internal header file, included by other library headers.
00027  *  Do not attempt to use it directly. @headername{mutex}
00028  */
00029 
00030 #ifndef _GLIBCXX_UNIQUE_LOCK_H
00031 #define _GLIBCXX_UNIQUE_LOCK_H 1
00032 
00033 #pragma GCC system_header
00034 
00035 #if __cplusplus < 201103L
00036 # include <bits/c++0x_warning.h>
00037 #else
00038 
00039 #include <chrono>
00040 #include <bits/move.h> // for std::swap
00041 
00042 namespace std _GLIBCXX_VISIBILITY(default)
00043 {
00044 _GLIBCXX_BEGIN_NAMESPACE_VERSION
00045 
00046   /**
00047    * @ingroup mutexes
00048    * @{
00049    */
00050 
00051   /** @brief A movable scoped lock type.
00052    *
00053    * A unique_lock controls mutex ownership within a scope. Ownership of the
00054    * mutex can be delayed until after construction and can be transferred
00055    * to another unique_lock by move construction or move assignment. If a
00056    * mutex lock is owned when the destructor runs ownership will be released.
00057    */
00058   template<typename _Mutex>
00059     class unique_lock
00060     {
00061     public:
00062       typedef _Mutex mutex_type;
00063 
00064       unique_lock() noexcept
00065       : _M_device(0), _M_owns(false)
00066       { }
00067 
00068       explicit unique_lock(mutex_type& __m)
00069       : _M_device(std::__addressof(__m)), _M_owns(false)
00070       {
00071         lock();
00072         _M_owns = true;
00073       }
00074 
00075       unique_lock(mutex_type& __m, defer_lock_t) noexcept
00076       : _M_device(std::__addressof(__m)), _M_owns(false)
00077       { }
00078 
00079       unique_lock(mutex_type& __m, try_to_lock_t)
00080       : _M_device(std::__addressof(__m)), _M_owns(_M_device->try_lock())
00081       { }
00082 
00083       unique_lock(mutex_type& __m, adopt_lock_t) noexcept
00084       : _M_device(std::__addressof(__m)), _M_owns(true)
00085       {
00086         // XXX calling thread owns mutex
00087       }
00088 
00089       template<typename _Clock, typename _Duration>
00090         unique_lock(mutex_type& __m,
00091                     const chrono::time_point<_Clock, _Duration>& __atime)
00092         : _M_device(std::__addressof(__m)),
00093           _M_owns(_M_device->try_lock_until(__atime))
00094         { }
00095 
00096       template<typename _Rep, typename _Period>
00097         unique_lock(mutex_type& __m,
00098                     const chrono::duration<_Rep, _Period>& __rtime)
00099         : _M_device(std::__addressof(__m)),
00100           _M_owns(_M_device->try_lock_for(__rtime))
00101         { }
00102 
00103       ~unique_lock()
00104       {
00105         if (_M_owns)
00106           unlock();
00107       }
00108 
00109       unique_lock(const unique_lock&) = delete;
00110       unique_lock& operator=(const unique_lock&) = delete;
00111 
00112       unique_lock(unique_lock&& __u) noexcept
00113       : _M_device(__u._M_device), _M_owns(__u._M_owns)
00114       {
00115         __u._M_device = 0;
00116         __u._M_owns = false;
00117       }
00118 
00119       unique_lock& operator=(unique_lock&& __u) noexcept
00120       {
00121         if(_M_owns)
00122           unlock();
00123 
00124         unique_lock(std::move(__u)).swap(*this);
00125 
00126         __u._M_device = 0;
00127         __u._M_owns = false;
00128 
00129         return *this;
00130       }
00131 
00132       void
00133       lock()
00134       {
00135         if (!_M_device)
00136           __throw_system_error(int(errc::operation_not_permitted));
00137         else if (_M_owns)
00138           __throw_system_error(int(errc::resource_deadlock_would_occur));
00139         else
00140           {
00141             _M_device->lock();
00142             _M_owns = true;
00143           }
00144       }
00145 
00146       bool
00147       try_lock()
00148       {
00149         if (!_M_device)
00150           __throw_system_error(int(errc::operation_not_permitted));
00151         else if (_M_owns)
00152           __throw_system_error(int(errc::resource_deadlock_would_occur));
00153         else
00154           {
00155             _M_owns = _M_device->try_lock();
00156             return _M_owns;
00157           }
00158       }
00159 
00160       template<typename _Clock, typename _Duration>
00161         bool
00162         try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
00163         {
00164           if (!_M_device)
00165             __throw_system_error(int(errc::operation_not_permitted));
00166           else if (_M_owns)
00167             __throw_system_error(int(errc::resource_deadlock_would_occur));
00168           else
00169             {
00170               _M_owns = _M_device->try_lock_until(__atime);
00171               return _M_owns;
00172             }
00173         }
00174 
00175       template<typename _Rep, typename _Period>
00176         bool
00177         try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
00178         {
00179           if (!_M_device)
00180             __throw_system_error(int(errc::operation_not_permitted));
00181           else if (_M_owns)
00182             __throw_system_error(int(errc::resource_deadlock_would_occur));
00183           else
00184             {
00185               _M_owns = _M_device->try_lock_for(__rtime);
00186               return _M_owns;
00187             }
00188          }
00189 
00190       void
00191       unlock()
00192       {
00193         if (!_M_owns)
00194           __throw_system_error(int(errc::operation_not_permitted));
00195         else if (_M_device)
00196           {
00197             _M_device->unlock();
00198             _M_owns = false;
00199           }
00200       }
00201 
00202       void
00203       swap(unique_lock& __u) noexcept
00204       {
00205         std::swap(_M_device, __u._M_device);
00206         std::swap(_M_owns, __u._M_owns);
00207       }
00208 
00209       mutex_type*
00210       release() noexcept
00211       {
00212         mutex_type* __ret = _M_device;
00213         _M_device = 0;
00214         _M_owns = false;
00215         return __ret;
00216       }
00217 
00218       bool
00219       owns_lock() const noexcept
00220       { return _M_owns; }
00221 
00222       explicit operator bool() const noexcept
00223       { return owns_lock(); }
00224 
00225       mutex_type*
00226       mutex() const noexcept
00227       { return _M_device; }
00228 
00229     private:
00230       mutex_type*       _M_device;
00231       bool              _M_owns;
00232     };
00233 
00234   /// Swap overload for unique_lock objects.
00235   template<typename _Mutex>
00236     inline void
00237     swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) noexcept
00238     { __x.swap(__y); }
00239 
00240   // @} group mutexes
00241 _GLIBCXX_END_NAMESPACE_VERSION
00242 } // namespace
00243 
00244 #endif // C++11
00245 #endif // _GLIBCXX_UNIQUE_LOCK_H