Turi Create  4.0
mutex.hpp
1 /* Copyright © 2017 Apple Inc. All rights reserved.
2  *
3  * Use of this source code is governed by a BSD-3-clause license that can
4  * be found in the LICENSE.txt file or at
5  * https://opensource.org/licenses/BSD-3-Clause
6  */
7 #ifndef TURI_MUTEX_HPP
8 #define TURI_MUTEX_HPP
9 
10 #include <core/parallel/pthread_h.h>
11 #include <core/logging/assertions.hpp>
12 #include <mutex>
13 
14 namespace turi {
15 
16 /**
17  * \ingroup threading
18  *
19  * Simple wrapper around pthread's mutex.
20  * Before you use, see \ref parallel_object_intricacies.
21  *
22  * Windows recursive mutex are annoyingly recursive.
23  * We need to prevent recursive locks. We do this by associating an
24  * addition boolean "locked" to the mutex.
25  * Hence in the event of a double lock, on Windows the behavior is slightly
26  * different. On Linux/Mac this will trigger a deadlock. On Windows,
27  * this will trigger an assertion failure.
28  */
29 class mutex {
30  public:
31  // mutable not actually needed
32  mutable pthread_mutex_t m_mut;
33 #ifdef _WIN32
34  mutable volatile bool locked = false;
35 #endif
36  /// constructs a mutex
37  mutex() {
38  int error = pthread_mutex_init(&m_mut, NULL);
39  ASSERT_MSG(!error, "Mutex create error %d", error);
40  }
41  /** Copy constructor which does not copy. Do not use!
42  Required for compatibility with some STL implementations (LLVM).
43  which use the copy constructor for vector resize,
44  rather than the standard constructor. */
45  mutex(const mutex&) {
46  int error = pthread_mutex_init(&m_mut, NULL);
47  ASSERT_MSG(!error, "Mutex create error %d", error);
48  }
49 
50  ~mutex() noexcept {
51  int error = pthread_mutex_destroy(&m_mut);
52  if (error) {
53  try {
54  std::cerr << "Mutex destroy error " << error << std::endl;
55  } catch (...) {
56  }
57  abort();
58  }
59  }
60 
61  // not copyable
62  void operator=(const mutex& m) {}
63  /// Acquires a lock on the mutex
64  inline void lock() const {
65  TURI_ATTRIBUTE_UNUSED_NDEBUG int error = pthread_mutex_lock( &m_mut );
66  DASSERT_MSG(!error, "Mutex lock error code: %d", error);
67 #ifdef _WIN32
68  DASSERT_TRUE(!locked);
69  locked = true;
70 #endif
71  }
72  /// Releases a lock on the mutex
73  inline void unlock() const {
74 #ifdef _WIN32
75  locked = false;
76 #endif
77 
78  TURI_ATTRIBUTE_UNUSED_NDEBUG int error = pthread_mutex_unlock(&m_mut);
79  DASSERT_MSG(!error, "Mutex unlock error %d", error);
80  }
81  /// Non-blocking attempt to acquire a lock on the mutex
82  inline bool try_lock() const {
83 #ifdef _WIN32
84  if (locked) return false;
85 #endif
86  return pthread_mutex_trylock(&m_mut) == 0;
87  }
88  friend class conditional;
89 }; // End of Mutex
90 
91 /**
92  * \ingroup threading
93  *
94  * Simple wrapper around pthread's recursive mutex.
95  * Before you use, see \ref parallel_object_intricacies.
96  */
98  public:
99  // mutable not actually needed
100  mutable pthread_mutex_t m_mut;
101  /// constructs a mutex
103  pthread_mutexattr_t attr;
104  int error = pthread_mutexattr_init(&attr);
105  ASSERT_TRUE(!error);
106  error = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
107  ASSERT_TRUE(!error);
108  error = pthread_mutex_init(&m_mut, &attr);
109  ASSERT_TRUE(!error);
110  pthread_mutexattr_destroy(&attr);
111  }
112  /** Copy constructor which does not copy. Do not use!
113  Required for compatibility with some STL implementations (LLVM).
114  which use the copy constructor for vector resize,
115  rather than the standard constructor. */
117  pthread_mutexattr_t attr;
118  int error = pthread_mutexattr_init(&attr);
119  ASSERT_TRUE(!error);
120  error = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
121  ASSERT_TRUE(!error);
122  error = pthread_mutex_init(&m_mut, &attr);
123  ASSERT_TRUE(!error);
124  pthread_mutexattr_destroy(&attr);
125  }
126 
127  ~recursive_mutex() {
128  TURI_ATTRIBUTE_UNUSED_NDEBUG int error = pthread_mutex_destroy(&m_mut);
129  DASSERT_TRUE(!error);
130  }
131 
132  // not copyable
133  void operator=(const recursive_mutex& m) {}
134 
135  /// Acquires a lock on the mutex
136  inline void lock() const {
137  TURI_ATTRIBUTE_UNUSED_NDEBUG int error = pthread_mutex_lock(&m_mut);
138  // if (error) std::cerr << "mutex.lock() error: " << error << std::endl;
139  DASSERT_TRUE(!error);
140  }
141  /// Releases a lock on the mutex
142  inline void unlock() const {
143  TURI_ATTRIBUTE_UNUSED_NDEBUG int error = pthread_mutex_unlock(&m_mut);
144  DASSERT_TRUE(!error);
145  }
146  /// Non-blocking attempt to acquire a lock on the mutex
147  inline bool try_lock() const { return pthread_mutex_trylock(&m_mut) == 0; }
148  friend class conditional;
149 }; // End of Mutex
150 
151 } // namespace turi
152 
153 #endif
recursive_mutex()
constructs a mutex
Definition: mutex.hpp:102
bool try_lock() const
Non-blocking attempt to acquire a lock on the mutex.
Definition: mutex.hpp:147
recursive_mutex(const recursive_mutex &)
Definition: mutex.hpp:116
mutex()
constructs a mutex
Definition: mutex.hpp:37
void lock() const
Acquires a lock on the mutex.
Definition: mutex.hpp:136
void lock() const
Acquires a lock on the mutex.
Definition: mutex.hpp:64
void unlock() const
Releases a lock on the mutex.
Definition: mutex.hpp:73
void unlock() const
Releases a lock on the mutex.
Definition: mutex.hpp:142
#define ASSERT_TRUE(cond)
Definition: assertions.hpp:309
bool try_lock() const
Non-blocking attempt to acquire a lock on the mutex.
Definition: mutex.hpp:82
mutex(const mutex &)
Definition: mutex.hpp:45
#define DASSERT_TRUE(cond)
Definition: assertions.hpp:364