proxygen
TimedMutex.h
Go to the documentation of this file.
1 /*
2  * Copyright 2015-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <folly/IntrusiveList.h>
19 #include <folly/SpinLock.h>
21 
22 namespace folly {
23 namespace fibers {
24 
30 class TimedMutex {
31  public:
33 
35  DCHECK(threadWaiters_.empty());
36  DCHECK(fiberWaiters_.empty());
37  DCHECK(notifiedFiber_ == nullptr);
38  }
39 
40  TimedMutex(const TimedMutex& rhs) = delete;
41  TimedMutex& operator=(const TimedMutex& rhs) = delete;
42  TimedMutex(TimedMutex&& rhs) = delete;
43  TimedMutex& operator=(TimedMutex&& rhs) = delete;
44 
45  // Lock the mutex. The thread / fiber is blocked until the mutex is free
46  void lock();
47 
48  // Lock the mutex. The thread / fiber will be blocked for a time duration.
49  //
50  // @return true if the mutex was locked, false otherwise
51  template <typename Rep, typename Period>
52  bool timed_lock(const std::chrono::duration<Rep, Period>& duration);
53 
54  // Try to obtain lock without blocking the thread or fiber
55  bool try_lock();
56 
57  // Unlock the mutex and wake up a waiter if there is one
58  void unlock();
59 
60  private:
61  enum class LockResult { SUCCESS, TIMEOUT, STOLEN };
62 
63  template <typename WaitFunc>
64  LockResult lockHelper(WaitFunc&& waitFunc);
65 
66  // represents a waiter waiting for the lock. The waiter waits on the
67  // baton until it is woken up by a post or timeout expires.
68  struct MutexWaiter {
71  };
72 
74 
75  folly::SpinLock lock_; //< lock to protect waiter list
76  bool locked_ = false; //< is this locked by some thread?
77  MutexWaiterList threadWaiters_; //< list of waiters
78  MutexWaiterList fiberWaiters_; //< list of waiters
79  MutexWaiter* notifiedFiber_{nullptr}; //< Fiber waiter which has been notified
80 };
81 
91 template <typename BatonType>
92 class TimedRWMutex {
93  public:
94  TimedRWMutex() = default;
95  ~TimedRWMutex() = default;
96 
97  TimedRWMutex(const TimedRWMutex& rhs) = delete;
98  TimedRWMutex& operator=(const TimedRWMutex& rhs) = delete;
99  TimedRWMutex(TimedRWMutex&& rhs) = delete;
100  TimedRWMutex& operator=(TimedRWMutex&& rhs) = delete;
101 
102  // Lock for shared access. The thread / fiber is blocked until the lock
103  // can be acquired.
104  void read_lock();
105 
106  // Like read_lock except the thread /fiber is blocked for a time duration
107  // @return true if locked successfully, false otherwise.
108  template <typename Rep, typename Period>
109  bool timed_read_lock(const std::chrono::duration<Rep, Period>& duration);
110 
111  // Like read_lock but doesn't block the thread / fiber if the lock can't
112  // be acquired.
113  // @return true if lock was acquired, false otherwise.
114  bool try_read_lock();
115 
116  // Obtain an exclusive lock. The thread / fiber is blocked until the lock
117  // is available.
118  void write_lock();
119 
120  // Like write_lock except the thread / fiber is blocked for a time duration
121  // @return true if locked successfully, false otherwise.
122  template <typename Rep, typename Period>
123  bool timed_write_lock(const std::chrono::duration<Rep, Period>& duration);
124 
125  // Like write_lock but doesn't block the thread / fiber if the lock cant be
126  // obtained.
127  // @return true if lock was acquired, false otherwise.
128  bool try_write_lock();
129 
130  // Wrapper for write_lock() for compatibility with Mutex
131  void lock() {
132  write_lock();
133  }
134 
135  // Realease the lock. The thread / fiber will wake up all readers if there are
136  // any. If there are waiting writers then only one of them will be woken up.
137  // NOTE: readers are given priority over writers (see above comment)
138  void unlock();
139 
140  // Downgrade the lock. The thread / fiber will wake up all readers if there
141  // are any.
142  void downgrade();
143 
144  class ReadHolder {
145  public:
146  explicit ReadHolder(TimedRWMutex& lock) : lock_(&lock) {
147  lock_->read_lock();
148  }
149 
151  if (lock_) {
152  lock_->unlock();
153  }
154  }
155 
156  ReadHolder(const ReadHolder& rhs) = delete;
157  ReadHolder& operator=(const ReadHolder& rhs) = delete;
158  ReadHolder(ReadHolder&& rhs) = delete;
159  ReadHolder& operator=(ReadHolder&& rhs) = delete;
160 
161  private:
163  };
164 
165  class WriteHolder {
166  public:
167  explicit WriteHolder(TimedRWMutex& lock) : lock_(&lock) {
168  lock_->write_lock();
169  }
170 
172  if (lock_) {
173  lock_->unlock();
174  }
175  }
176 
177  WriteHolder(const WriteHolder& rhs) = delete;
178  WriteHolder& operator=(const WriteHolder& rhs) = delete;
179  WriteHolder(WriteHolder&& rhs) = delete;
180  WriteHolder& operator=(WriteHolder&& rhs) = delete;
181 
182  private:
184  };
185 
186  private:
187  // invariants that must hold when the lock is not held by anyone
189  assert(readers_ == 0);
190  assert(read_waiters_.empty());
191  assert(write_waiters_.empty());
192  }
193 
194  // Different states the lock can be in
195  enum class State {
196  UNLOCKED,
197  READ_LOCKED,
198  WRITE_LOCKED,
199  };
200 
201  typedef boost::intrusive::list_member_hook<> MutexWaiterHookType;
202 
203  // represents a waiter waiting for the lock.
204  struct MutexWaiter {
205  BatonType baton;
206  MutexWaiterHookType hook;
207  };
208 
209  typedef boost::intrusive::
210  member_hook<MutexWaiter, MutexWaiterHookType, &MutexWaiter::hook>
212 
213  typedef boost::intrusive::list<
214  MutexWaiter,
216  boost::intrusive::constant_time_size<true>>
218 
219  folly::SpinLock lock_; //< lock protecting the internal state
220  // (state_, read_waiters_, etc.)
221  State state_ = State::UNLOCKED;
222 
223  uint32_t readers_ = 0; //< Number of readers who have the lock
224 
225  MutexWaiterList write_waiters_; //< List of thread / fibers waiting for
226  // exclusive access
227 
228  MutexWaiterList read_waiters_; //< List of thread / fibers waiting for
229  // shared access
230 };
231 } // namespace fibers
232 } // namespace folly
233 
MutexWaiterList read_waiters_
Definition: TimedMutex.h:228
boost::intrusive::list< MutexWaiter, MutexWaiterHook, boost::intrusive::constant_time_size< true > > MutexWaiterList
Definition: TimedMutex.h:217
folly::SpinLock lock_
Definition: TimedMutex.h:75
MutexWaiterList fiberWaiters_
Definition: TimedMutex.h:78
folly::IntrusiveListHook hook
Definition: TimedMutex.h:70
MutexWaiterList write_waiters_
Definition: TimedMutex.h:225
boost::intrusive::list_member_hook MutexWaiterHookType
Definition: TimedMutex.h:201
folly::IntrusiveList< MutexWaiter,&MutexWaiter::hook > MutexWaiterList
Definition: TimedMutex.h:73
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
FOLLY_ALWAYS_INLINE void unlock() const noexcept
Definition: SpinLock.h:52
FOLLY_PUSH_WARNING RHS rhs
Definition: Traits.h:649
TimedMutex & operator=(const TimedMutex &rhs)=delete
boost::intrusive::list_member_hook< boost::intrusive::link_mode< boost::intrusive::auto_unlink >> IntrusiveListHook
Definition: IntrusiveList.h:32
boost::intrusive::member_hook< MutexWaiter, MutexWaiterHookType,&MutexWaiter::hook > MutexWaiterHook
Definition: TimedMutex.h:211
Encoder::MutableCompressedList list
LockResult lockHelper(WaitFunc &&waitFunc)
boost::intrusive::list< T, boost::intrusive::member_hook< T, IntrusiveListHook, PtrToMember >, boost::intrusive::constant_time_size< false >> IntrusiveList
Definition: IntrusiveList.h:68
MutexWaiterList threadWaiters_
Definition: TimedMutex.h:77
bool timed_lock(const std::chrono::duration< Rep, Period > &duration)
MutexWaiter * notifiedFiber_
Definition: TimedMutex.h:79