atscppapi  1.0.9
C++ wrapper for Apache Traffic Server API
 All Classes Files Functions Enumerations Enumerator Macros
Mutex.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 LinkedIn Corp. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
4  * except in compliance with the License. You may obtain a copy of the license at
5  * http://www.apache.org/licenses/LICENSE-2.0
6  *
7  * Unless required by applicable law or agreed to in writing, software distributed under the
8  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
9  * either express or implied.
10  *
11  */
12 
13 /**
14  * @file Mutex.h
15  * @author Brian Geffon
16  * @author Manjesh Nilange
17  * @brief Contains Mutex related classes for creating a Mutex and locking a Mutex in a specific scope.
18  */
19 
20 #pragma once
21 #ifndef ATSCPPAPI_MUTEX_H_
22 #define ATSCPPAPI_MUTEX_H_
23 
24 #include <pthread.h>
25 #include <atscppapi/noncopyable.h>
26 #include <atscppapi/shared_ptr.h>
27 
28 namespace atscppapi {
29 
30 /**
31  * @brief A mutex is mutual exclusion: a blocking lock.
32  *
33  * The Mutex class uses pthreads for its implmentation.
34  *
35  * @see ScopedMutexLock
36  * @see ScopedMutexTryLock
37  * @see ScopedSharedMutexLock
38  * @see ScopedSharedMutexTryLock
39  */
40 class Mutex: noncopyable {
41 public:
42 
43  /**
44  * The available types of Mutexes.
45  */
46  enum Type {
47  TYPE_NORMAL = 0, /**< This type of Mutex will deadlock if locked by a thread already holding the lock */
48  TYPE_RECURSIVE, /**< This type of Mutex will allow a thread holding the lock to lock it again; however, it must be unlocked the same number of times */
49  TYPE_ERROR_CHECK /**< This type of Mutex will return errno = EDEADLCK if a thread would deadlock by taking the lock after it already holds it */
50  };
51 
52  /**
53  * Create a mutex
54  *
55  * @param type The Type of Mutex to create, the default is TYPE_NORMAL.
56  * @see Type
57  */
59  pthread_mutexattr_t attr;
60  pthread_mutexattr_init(&attr);
61 
62  switch(type) {
63  case TYPE_RECURSIVE:
64  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
65  break;
66  case TYPE_ERROR_CHECK:
67  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
68  break;
69  case TYPE_NORMAL:
70  default:
71  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
72  break;
73  }
74 
75  pthread_mutex_init(&mutex, &attr);
76  }
77 
78  ~Mutex() {
79  pthread_mutex_destroy(&mutex);
80  }
81 
82  /**
83  * Try to take the lock, this call will NOT block if the mutex cannot be taken.
84  * @return Returns true if the lock was taken, false if it was not. This call obviously will not block.
85  */
86  bool tryLock() {
87  return !pthread_mutex_trylock(&mutex);
88  }
89 
90  /**
91  * Block until the lock is taken, when this call returns the thread will be holding the lock.
92  */
93  void lock() {
94  pthread_mutex_lock(&mutex);
95  }
96 
97  /**
98  * Unlock the lock, this call is nonblocking.
99  */
100  void unlock() {
101  pthread_mutex_unlock(&mutex);
102  }
103 private:
104  pthread_mutex_t mutex; /**< Internal mutex identifier */
105 };
106 
107 /**
108  * @brief Take a Mutex reference and lock inside a scope and unlock when the scope is exited.
109  *
110  * This is an RAII implementation which will lock a mutex at the start of the
111  * scope and unlock it when the scope is exited.
112  *
113  * @see Mutex
114  */
115 class ScopedMutexLock: noncopyable {
116 public:
117  /**
118  * Create the scoped mutex lock, once this object is constructed the lock will be held by the thread.
119  * @param mutex a reference to a Mutex.
120  */
121  explicit ScopedMutexLock(Mutex &mutex) :
122  mutex_(mutex) {
123  mutex_.lock();
124  }
125 
126  /**
127  * Unlock the mutex.
128  */
130  mutex_.unlock();
131  }
132 private:
133  Mutex &mutex_;
134 };
135 
136 /**
137  * @brief Take a shared_ptr to a Mutex and lock inside a scope and unlock when the scope is exited.
138  *
139  * This is an RAII implementation which will lock a mutex at the start of the
140  * scope and unlock it when the scope is exited.
141  *
142  * @see Mutex
143  */
144 class ScopedSharedMutexLock: noncopyable {
145 public:
146  /**
147  * Create the scoped mutex lock, once this object is constructed the lock will be held by the thread.
148  * @param mutex a shared pointer to a Mutex.
149  */
150  explicit ScopedSharedMutexLock(shared_ptr<Mutex> mutex) :
151  mutex_(mutex) {
152  mutex_->lock();
153  }
154 
155  /**
156  * Unlock the mutex.
157  */
159  mutex_->unlock();
160  }
161 private:
162  shared_ptr<Mutex> mutex_;
163 };
164 
165 /**
166  * @brief Take a Mutex reference and try to lock inside a scope and unlock when the scope is exited (if the lock was taken).
167  *
168  * This is an RAII implementation which will lock a mutex at the start of the
169  * scope and unlock it when the scope is exited if the lock was taken.
170  *
171  * @see Mutex
172  */
173 class ScopedMutexTryLock: noncopyable {
174 public:
175  /**
176  * Try to create the scoped mutex lock, if you should check hasLock() to determine if this object was successfully able to take the lock.
177  * @param mutex a shared pointer to a Mutex.
178  */
179  explicit ScopedMutexTryLock(Mutex &mutex) :
180  mutex_(mutex), has_lock_(false) {
181  has_lock_ = mutex_.tryLock();
182  }
183 
184  /**
185  * Unlock the mutex (if we hold the lock)
186  */
188  if (has_lock_) {
189  mutex_.unlock();
190  }
191  }
192 
193  /**
194  * @return True if the lock was taken, False if it was not taken.
195  */
196  bool hasLock() {
197  return has_lock_;
198  }
199 private:
200  Mutex &mutex_;
201  bool has_lock_;
202 };
203 
204 /**
205  * @brief Take a shared_ptr to a Mutex and try to lock inside a scope and unlock when the scope is exited (if the lock was taken).
206  *
207  * This is an RAII implementation which will lock a mutex at the start of the
208  * scope and unlock it when the scope is exited if the lock was taken.
209  *
210  * @see Mutex
211  */
212 class ScopedSharedMutexTryLock: noncopyable {
213 public:
214  /**
215  * Try to create the scoped mutex lock, if you should check hasLock() to determine if this object was successfully able to take the lock.
216  * @param mutex a shared pointer to a Mutex.
217  */
218  explicit ScopedSharedMutexTryLock(shared_ptr<Mutex> mutex) :
219  mutex_(mutex), has_lock_(false) {
220  has_lock_ = mutex_->tryLock();
221  }
222 
223  /**
224  * Unlock the mutex (if we hold the lock)
225  */
227  if (has_lock_) {
228  mutex_->unlock();
229  }
230  }
231 
232  /**
233  * @return True if the lock was taken, False if it was not taken.
234  */
235  bool hasLock() {
236  return has_lock_;
237  }
238 private:
239  shared_ptr<Mutex> mutex_;
240  bool has_lock_;
241 };
242 
243 } /* atscppapi */
244 
245 
246 #endif /* ATSCPPAPI_MUTEX_H_ */