MiniOB 1
MiniOB is one mini database, helping developers to learn how database works.
载入中...
搜索中...
未找到
mutex.h
1/* Copyright (c) 2021 OceanBase and/or its affiliates. All rights reserved.
2miniob is licensed under Mulan PSL v2.
3You can use this software according to the terms and conditions of the Mulan PSL v2.
4You may obtain a copy of Mulan PSL v2 at:
5 http://license.coscl.org.cn/MulanPSL2
6THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
7EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
8MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
9See the Mulan PSL v2 for more details. */
10
11//
12// Created by Longda on 2010
13//
14
15#pragma once
16
17#include <condition_variable>
18#include <errno.h>
19#include <map>
20#include <mutex>
21#include <pthread.h>
22#include <shared_mutex>
23#include <sstream>
24#include <string.h>
25#include <string>
26#include <sys/types.h>
27#include <unordered_map>
28
29#include "common/lang/thread.h"
30#include "common/log/log.h"
31
32using std::call_once;
33using std::condition_variable;
34using std::lock_guard;
35using std::mutex;
36using std::once_flag;
37using std::scoped_lock;
38using std::shared_mutex;
39using std::unique_lock;
40
41namespace common {
42
43#define MUTEX_LOG LOG_DEBUG
44
46{
47public:
48 static void check(pthread_mutex_t *mutex, const long long threadId, const char *file, const int line);
49 static void lock(pthread_mutex_t *mutex, const long long threadId, const char *file, const int line);
50 static void tryLock(pthread_mutex_t *mutex, const long long threadId, const char *file, const int line);
51 static void unlock(pthread_mutex_t *mutex, const long long threadId, const char *file, const int line);
52
53 static void toString(string &result);
54
55 class LockID
56 {
57 public:
58 LockID(const long long threadId, const char *file, const int line) : mFile(file), mThreadId(threadId), mLine(line)
59 {}
60 LockID() : mFile(), mThreadId(0), mLine(0) {}
61
62 string toString()
63 {
64 ostringstream oss;
65
66 oss << "threaId:" << mThreadId << ",file name:" << mFile << ",line:" << mLine;
67
68 return oss.str();
69 }
70
71 public:
72 string mFile;
73 const long long mThreadId;
74 int mLine;
75 };
76
77 static void foundDeadLock(LockID &current, LockID &other, pthread_mutex_t *otherWaitMutex);
78
79 static bool deadlockCheck(LockID &current, set<pthread_mutex_t *> &ownMutexs, LockID &other, int recusiveNum);
80
81 static bool deadlockCheck(pthread_mutex_t *mutex, const long long threadId, const char *file, const int line);
82
83 static bool checkLockTimes(pthread_mutex_t *mutex, const char *file, const int line);
84
85 static void insertLock(pthread_mutex_t *mutex, const long long threadId, const char *file, const int line);
86
87 static void setMaxBlockThreads(int blockNum) { mMaxBlockTids = blockNum; }
88
89public:
90 static set<pthread_mutex_t *> mEnableRecurisives;
91
92protected:
93 static map<pthread_mutex_t *, LockID> mLocks;
94 static map<pthread_mutex_t *, int> mWaitTimes;
95 static map<long long, pthread_mutex_t *> mWaitLocks;
96 static map<long long, set<pthread_mutex_t *>> mOwnLocks;
97
98 static pthread_rwlock_t mMapMutex;
99 static int mMaxBlockTids;
100};
101
102// Open this macro in Makefile
103#ifndef DEBUG_LOCK
104
105#define MUTEXT_STATIC_INIT() PTHREAD_MUTEX_INITIALIZER
106#define MUTEX_INIT(lock, attr) pthread_mutex_init(lock, attr)
107#define MUTEX_DESTROY(lock) pthread_mutex_destroy(lock)
108#define MUTEX_LOCK(lock) pthread_mutex_lock(lock)
109#define MUTEX_UNLOCK(lock) pthread_mutex_unlock(lock)
110#define MUTEX_TRYLOCK(lock) pthread_mutex_trylock(lock)
111
112#define COND_INIT(cond, attr) pthread_cond_init(cond, attr)
113#define COND_DESTROY(cond) pthread_cond_destroy(cond)
114#define COND_WAIT(cond, mutex) pthread_cond_wait(cond, mutex)
115#define COND_WAIT_TIMEOUT(cond, mutex, time, ret) ret = pthread_cond_timedwait(cond, mutex, time)
116#define COND_SIGNAL(cond) pthread_cond_signal(cond)
117#define COND_BRAODCAST(cond) pthread_cond_broadcast(cond)
118
119#else // DEBUG_LOCK
120
121#define MUTEX_STATIC_INIT() \
122 PTHREAD_MUTEX_INITIALIZER; \
123 LOG_INFO("PTHREAD_MUTEX_INITIALIZER");
124
125#if defined(__MACH__)
126
127#define MUTEX_INIT(lock, attr) \
128 ({ \
129 LOG_INFO("pthread_mutex_init %p", lock); \
130 if (attr != NULL) { \
131 int type; \
132 pthread_mutexattr_gettype(attr, &type); \
133 if (type == PTHREAD_MUTEX_RECURSIVE) { \
134 LockTrace::mEnableRecurisives.insert(lock); \
135 } \
136 } \
137 int result = pthread_mutex_init(lock, attr); \
138 result; \
139 })
140
141#else
142
143#define MUTEX_INIT(lock, attr) \
144 ({ \
145 LOG_INFO("pthread_mutex_init %p", lock); \
146 if (attr != NULL) { \
147 int type; \
148 pthread_mutexattr_gettype(attr, &type); \
149 if (type == PTHREAD_MUTEX_RECURSIVE_NP) { \
150 LockTrace::mEnableRecurisives.insert(lock); \
151 } \
152 } \
153 int result = pthread_mutex_init(lock, attr); \
154 result; \
155 })
156#endif
157
158#define MUTEX_DESTROY(lock) \
159 ({ \
160 LockTrace::mEnableRecurisives.erase(lock); \
161 int result = pthread_mutex_destroy(lock); \
162 LOG_INFO("pthread_mutex_destroy %p", lock); \
163 result; \
164 })
165
166#define MUTEX_LOCK(mutex) \
167 ({ \
168 LockTrace::check(mutex, gettid(), __FILE__, __LINE__); \
169 int result = pthread_mutex_lock(mutex); \
170 LockTrace::lock(mutex, gettid(), __FILE__, __LINE__); \
171 if (result) { \
172 LOG_ERROR("Failed to lock %p, rc %d:%s", mutex, errno, strerror(errno)); \
173 } \
174 result; \
175 })
176
177#define MUTEX_TRYLOCK(mutex) \
178 ({ \
179 LockTrace::check(mutex, gettid(), __FILE__, __LINE__); \
180 int result = pthread_mutex_trylock(mutex); \
181 if (result == 0) { \
182 LockTrace::lock(mutex, gettid(), __FILE__, __LINE__); \
183 } \
184 result; \
185 })
186
187#define MUTEX_UNLOCK(lock) \
188 ({ \
189 int result = pthread_mutex_unlock(lock); \
190 LockTrace::unlock(lock, gettid(), __FILE__, __LINE__); \
191 MUTEX_LOG("mutex:%p has been ulocked", lock); \
192 if (result) { \
193 LOG_ERROR("Failed to unlock %p, rc %d:%s", lock, errno, strerror(errno)); \
194 } \
195 result; \
196 })
197
198#define COND_INIT(cond, attr) \
199 ({ \
200 LOG_INFO("pthread_cond_init"); \
201 int result = pthread_cond_init(cond, attr); \
202 result; \
203 })
204
205#define COND_DESTROY(cond) \
206 ({ \
207 int result = pthread_cond_destroy(cond); \
208 LOG_INFO("pthread_cond_destroy"); \
209 result; \
210 })
211
212#define COND_WAIT(cond, mutex) \
213 ({ \
214 MUTEX_LOG("pthread_cond_wait, cond:%p, mutex:%p", cond, mutex); \
215 LockTrace::unlock(mutex, gettid(), __FILE__, __LINE__); \
216 int result = pthread_cond_wait(cond, mutex); \
217 LockTrace::check(mutex, gettid(), __FILE__, __LINE__); \
218 LockTrace::lock(mutex, gettid(), __FILE__, __LINE__); \
219 MUTEX_LOG("Lock %p under pthread_cond_wait", mutex); \
220 result; \
221 })
222
223#define COND_WAIT_TIMEOUT(cond, mutex, time, ret) \
224 ({ \
225 MUTEX_LOG("pthread_cond_timedwait, cond:%p, mutex:%p", cond, mutex); \
226 LockTrace::unlock(mutex, gettid(), __FILE__, __LINE__); \
227 int result = pthread_cond_timedwait(cond, mutex, time); \
228 if (result == 0) { \
229 LockTrace::check(mutex, gettid(), __FILE__, __LINE__); \
230 LockTrace::lock(mutex, gettid(), __FILE__, __LINE__); \
231 MUTEX_LOG("Lock %p under pthread_cond_wait", mutex); \
232 } \
233 result; \
234 })
235
236#define COND_SIGNAL(cond) \
237 ({ \
238 int result = pthread_cond_signal(cond); \
239 MUTEX_LOG("pthread_cond_signal, cond:%p", cond); \
240 result; \
241 })
242
243#define COND_BRAODCAST(cond) \
244 ({ \
245 int result = pthread_cond_broadcast(cond); \
246 MUTEX_LOG("pthread_cond_broadcast, cond:%p", cond); \
247 result; \
248 })
249
250#endif // DEBUG_LOCK
251
252class DebugMutex final
253{
254public:
255 DebugMutex() = default;
256 ~DebugMutex() = default;
257
258 void lock();
259 void unlock();
260
261private:
262#ifdef DEBUG
263 mutex lock_;
264#endif
265};
266
267class Mutex final
268{
269public:
270 Mutex() = default;
271 ~Mutex() = default;
272
273 void lock();
274 bool try_lock();
275 void unlock();
276
277private:
278#ifdef CONCURRENCY
279 mutex lock_;
280#endif
281};
282
283class SharedMutex final
284{
285public:
286 SharedMutex() = default;
287 ~SharedMutex() = default;
288
289 void lock(); // lock exclusive
290 bool try_lock();
291 void unlock(); // unlock exclusive
292
293 void lock_shared();
294 bool try_lock_shared();
295 void unlock_shared();
296
297private:
298#ifdef CONCURRENCY
299 shared_mutex lock_;
300#endif
301};
302
310{
311public:
312 RecursiveSharedMutex() = default;
313 ~RecursiveSharedMutex() = default;
314
315 void lock_shared();
316 bool try_lock_shared();
317 void unlock_shared();
318
319 void lock();
320 void unlock();
321
322private:
323#ifdef CONCURRENCY
324 mutex mutex_;
325 condition_variable shared_lock_cv_;
326 condition_variable exclusive_lock_cv_;
327 int shared_lock_count_ = 0;
328 int exclusive_lock_count_ = 0;
329 thread::id recursive_owner_;
330 int recursive_count_ = 0; // 表示当前线程加写锁加了多少次
331#endif // CONCURRENCY
332};
333
334} // namespace common
Definition: mutex.h:253
Definition: mutex.h:56
Definition: mutex.h:46
Definition: mutex.h:268
Definition: mutex.h:310
Definition: mutex.h:284