Ocean
Loading...
Searching...
No Matches
Lock.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#ifndef META_OCEAN_BASE_LOCK_H
9#define META_OCEAN_BASE_LOCK_H
10
11#include "ocean/base/Base.h"
12
13#if defined(_WINDOWS)
14 #include <winsock2.h>
15 #include <windows.h>
16#else
17 #include <pthread.h>
18#endif
19
20namespace Ocean
21{
22
23/**
24 * This class implements a recursive lock object.
25 * You can either explicitly lock and unlock an Lock object by using the appropriated functions.<br>
26 * However, it's recommended to use the corresponding scope classes for this lock object.
27 * @see TemplatedLock, ScopedLock, TemplatedScopedLock, TemporaryScopedLock, OptionalScopedLock.
28 * @ingroup base
29 */
30class OCEAN_BASE_EXPORT Lock
31{
32 public:
33
34 /**
35 * Creates a new lock object.
36 */
37 inline Lock();
38
39 /**
40 * Destructs a lock object.
41 */
42 inline ~Lock();
43
44 /**
45 * Locks the critical section.
46 */
47 inline void lock();
48
49 /**
50 * Unlocks the critical section.
51 */
52 inline void unlock();
53
54 /**
55 * Returns whether this critical section is locked by another thread.
56 * @return True, if so
57 */
58 inline bool isLocked();
59
60 protected:
61
62 /**
63 * Disabled copy constructor.
64 * @param lock The lock object to be copied
65 */
66 Lock(const Lock& lock) = delete;
67
68 /**
69 * Disabled assign operator.
70 * @param lock The lock object to be assigned
71 * @return Reference to this object
72 */
73 Lock& operator=(const Lock& lock) = delete;
74
75 protected:
76
77#if defined(_WINDOWS)
78
79 /// Critical section object of windows.
80 CRITICAL_SECTION criticalSection_;
81
82#else
83
84 /// Pthread mutex object.
85 pthread_mutex_t mutex_;
86
87#endif
88
89};
90
91/**
92 * This class implements a template-based recursive lock object.
93 * The class allows to e.g., implement classes which can be thread-safe or not based on a template parameter.
94 * @tparam tActive True, to activate the lock; False, to avoid using the lock at all
95 * @ingroup base
96 */
97template <bool tActive>
98class TemplatedLock : public Lock
99{
100 public:
101
102 /**
103 * Creates a new lock object.
104 */
105 TemplatedLock() = default;
106};
107
108/**
109 * Specialization of the TemplatedLock class.
110 * This class does nothing.
111 * @ingroup base
112 */
113template <>
114class TemplatedLock<false>
115{
116 public:
117
118 /**
119 * Creates a new lock object.
120 */
121 TemplatedLock() = default;
122
123 protected:
124
125 /**
126 * Disabled copy constructor.
127 * @param lock The lock object to be copied
128 */
130
131 /**
132 * Disabled assign operator.
133 * @param lock The lock object to be assigned
134 * @return Reference to this object
135 */
137};
138
139/**
140 * This class implements a scoped lock object for recursive lock objects.
141 * The application of a scoped lock object ensures that a lock will be unlocked in any case if the scope (in which the object exists) ends.<br>
142 * Thus, possible dead locks can be avoided (e.g., if a function returns while the before the unlock() function of the Lock object is invoke or if an exception is thrown but not intercepted).
143 * @see Lock, TemplatedScopedLock, TemporaryScopedLock, OptionalScopedLock.
144 * @ingroup base
145 */
146class OCEAN_BASE_EXPORT ScopedLock
147{
148 public:
149
150 /**
151 * Creates a new scoped lock object by a given lock object.
152 * @param lock The lock object used for locking
153 */
154 explicit inline ScopedLock(Lock& lock);
155
156 /**
157 * Destructs a scoped lock and unlocks the internal lock object.
158 */
159 inline ~ScopedLock();
160
161 protected:
162
163 /**
164 * Disabled accessible copy operator.
165 * @param object The object to copy
166 */
167 ScopedLock(const ScopedLock& object) = delete;
168
169 /**
170 * Disabled accessible assigns operator.
171 * @param object The right object
172 * @return Reference to this object
173 */
174 ScopedLock& operator=(const ScopedLock& object) = delete;
175
176 protected:
177
178 /// Lock object which is locked during the existence of this scoped lock object.
180};
181
182/**
183 * This class implements a recursive scoped lock object that is activated by a boolean template parameter.
184 * @tparam tActive True, to active the scoped lock, false to deactivate the scoped lock
185 * @see Lock, ScopedLock, TemporaryScopedLock, OptionalScopedLock.
186 * @ingroup base
187 */
188template <bool tActive>
190{
191 public:
192
193 /**
194 * Creates a new scoped lock object by a given lock object.
195 * @param lock The lock object used for locking
196 */
197 explicit inline TemplatedScopedLock(Lock& lock);
198
199 /**
200 * Creates a new scoped lock object by a given lock object.
201 * @param lock The lock object used for locking
202 */
203 explicit inline TemplatedScopedLock(TemplatedLock<tActive>& lock);
204
205 /**
206 * Destructs a scoped lock and unlocks the internal lock object.
207 */
208 inline ~TemplatedScopedLock();
209
210 protected:
211
212 /**
213 * Disabled accessible copy operator.
214 * @param object The object to copy
215 */
217
218 /**
219 * Disabled accessible assigns operator.
220 * @param object The right object
221 * @return Reference to this object
222 */
224
225 protected:
226
227 /// Lock object which is locked during the existence of this scoped lock object.
229};
230
231/**
232 * Specialization of the TemplatedScopedLock class.
233 * This class does nothing.
234 * @ingroup base
235 */
236template <>
238{
239 public:
240
241 /**
242 * Creates a new scoped lock object by a given lock object.
243 * @param lock The lock object used for locking
244 */
245 explicit inline TemplatedScopedLock(Lock& lock)
246 {
247 OCEAN_SUPPRESS_UNUSED_WARNING(lock);
248 }
249
250 /**
251 * Creates a new scoped lock object by a given lock object.
252 * @param lock The lock object used for locking
253 */
255 {
256 OCEAN_SUPPRESS_UNUSED_WARNING(lock);
257 }
258};
259
260/**
261 * This class implements a recursive scoped lock object allowing to release the lock before the scoped object itself is released.
262 * @see Lock, ScopedLock, TemplatedScopedLock, OptionalScopedLock.
263 * @ingroup base
264 */
265class OCEAN_BASE_EXPORT TemporaryScopedLock
266{
267 public:
268
269 /**
270 * Creates a new scoped lock object which is not locked yet.
271 */
273
274 /**
275 * Creates a new scoped lock object by a given lock object.
276 * @param lock The lock object used for locking
277 */
278 explicit inline TemporaryScopedLock(Lock& lock);
279
280 /**
281 * Destructs a scoped lock and unlocks the internal lock object (if still locked).
282 */
283 inline ~TemporaryScopedLock();
284
285 /**
286 * Returns the lock object which (if existing) is locked during the existence of this scoped lock object.
287 * @return The associated lock object, nullptr if this object is already released (or was never locked)
288 */
289 [[nodiscard]] inline Lock* lock() const;
290
291 /**
292 * Explicitly releases the lock before the scoped lock object is released.
293 */
294 inline void release();
295
296 /**
297 * Re-locks this scoped lock with a given lock.
298 * This scoped lock must be released before re-locking it again.
299 * @param lock The lock to be used for locking
300 * @see isReleased().
301 */
302 inline void relock(Lock& lock);
303
304 /**
305 * Returns whether this scoped lock is released already.
306 * @return True, if so
307 */
308 inline bool isReleased() const;
309
310 protected:
311
312 /**
313 * Disabled accessible copy operator.
314 * @param object The object to copy
315 */
316 inline TemporaryScopedLock(const TemporaryScopedLock& object) = delete;
317
318 /**
319 * Disabled accessible assigns operator.
320 * @param object The right object
321 * @return Reference to this object
322 */
323 inline TemporaryScopedLock& operator=(const TemporaryScopedLock& object) = delete;
324
325 protected:
326
327 /// Lock object which is locked during the existence of this scoped lock object.
328 Lock* lock_ = nullptr;
329};
330
331/**
332 * This class implements a scoped lock object that locks two lock objects in a deterministic order based on their memory addresses.
333 * This prevents potential deadlocks when two threads attempt to lock the same pair of locks in different orders.
334 * @tparam TScopedLock The type of scoped lock object, e.g., ScopedLock
335 * @tparam TLock The underlying lock type
336 * @see Lock, ScopedLock, TemplatedScopedLock.
337 * @ingroup base
338 */
339template <typename TScopedLock, typename TLock = Lock>
341{
342 public:
343
344 /**
345 * Creates a new dual scoped lock object based on two given lock objects.
346 * The locks will be acquired in a deterministic order based on their memory addresses to prevent deadlock.
347 * @param lockA The first lock object
348 * @param lockB The second lock object, must not be the same as the first lock object
349 */
350 explicit inline DualScopedLockT(TLock& lockA, TLock& lockB);
351
352 /**
353 * Destructs the dual scoped lock and unlocks both internal lock objects in reverse order.
354 */
355 ~DualScopedLockT() = default;
356
357 protected:
358
359 /**
360 * Disabled accessible copy operator.
361 * @param object The object to copy
362 */
364
365 /**
366 * Disabled accessible assigns operator.
367 * @param object The right object
368 * @return Reference to this object
369 */
371
372 protected:
373
374 /// Scopedlock object holding a lock on the lock with the lowest memory address.
375 TScopedLock scopedLockFirst_;
376
377 /// Scoped lock object holding a lock on the lock with the highest memory address.
378 TScopedLock scopedLockSecond_;
379};
380
381/**
382 * This class implements an optional recursive scoped lock object locking the lock object only if it's defined.
383 * @see Lock, ScopedLock, TemplatedScopedLock, TemporaryScopedLock.
384 * @ingroup base
385 */
386class OCEAN_BASE_EXPORT OptionalScopedLock
387{
388 public:
389
390 /**
391 * Creates a new optional scoped lock object by a given lock object.
392 * @param lock Optional lock object used for locking, otherwise nullptr
393 */
394 explicit inline OptionalScopedLock(Lock* lock);
395
396 /**
397 * Creates a new optional scoped lock object by a given lock object and a boolean statement whether the lock is invoked or not.
398 * @param lock The lock object used for locking
399 * @param apply True, to invoke the lock; False, to avoid the locking
400 */
401 inline OptionalScopedLock(Lock& lock, const bool apply);
402
403 /**
404 * Destructs an optional scoped lock and unlocks the internal lock object if defined.
405 */
406 inline ~OptionalScopedLock();
407
408 /**
409 * Returns the lock object which (if existing) is locked during the existence of this scoped lock object.
410 * @return The associated lock object, nullptr if no lock object was provided when this object was created
411 */
412 [[nodiscard]] inline Lock* lock() const;
413
414 protected:
415
416 /**
417 * Disabled accessible copy operator.
418 * @param object The object to copy
419 */
420 inline OptionalScopedLock(const OptionalScopedLock& object) = delete;
421
422 /**
423 * Disabled accessible assigns operator.
424 * @param object The right object
425 * @return Reference to this object
426 */
427 inline OptionalScopedLock& operator=(const OptionalScopedLock& object) = delete;
428
429 protected:
430
431 /// Lock object which is locked during the existence of this scoped lock object.
432 Lock* lock_ = nullptr;
433};
434
436{
437#if defined(_WINDOWS)
438
439 InitializeCriticalSection(&criticalSection_);
440
441#elif defined(__APPLE__) || defined(__linux__) || defined(__EMSCRIPTEN__)
442
443 pthread_mutexattr_t mutexAttribute;
444 pthread_mutexattr_init(&mutexAttribute);
445 pthread_mutexattr_settype(&mutexAttribute, PTHREAD_MUTEX_RECURSIVE);
446 pthread_mutex_init(&mutex_, &mutexAttribute);
447
448#else
449
450 pthread_mutexattr_t mutexAttribute = PTHREAD_MUTEX_RECURSIVE;
451 pthread_mutex_init(&mutex_, &mutexAttribute);
452
453#endif
454
455}
456
458{
459
460#if defined(_WINDOWS)
461
462 ocean_assert(criticalSection_.RecursionCount == 0);
463 DeleteCriticalSection(&criticalSection_);
464
465#else
466
467 pthread_mutex_destroy(&mutex_);
468
469#endif
470
471}
472
473inline void Lock::lock()
474{
475#if defined(_WINDOWS)
476
477 EnterCriticalSection(&criticalSection_);
478
479#else
480
481 pthread_mutex_lock(&mutex_);
482
483#endif
484
485}
486
487inline void Lock::unlock()
488{
489
490#if defined(_WINDOWS)
491
492 LeaveCriticalSection(&criticalSection_);
493
494#else
495
496 pthread_mutex_unlock(&mutex_);
497
498#endif
499
500}
501
502inline bool Lock::isLocked()
503{
504#if defined(_WINDOWS)
505
506 if (TryEnterCriticalSection(&criticalSection_) == TRUE)
507 {
508 LeaveCriticalSection(&criticalSection_);
509 return false;
510 }
511
512#else
513
514 if (pthread_mutex_trylock(&mutex_) == 0)
515 {
516 pthread_mutex_unlock(&mutex_);
517 return false;
518 }
519
520#endif
521
522 return true;
523}
524
526 lock_(lock)
527{
528 lock_.lock();
529}
530
532{
533 lock_.unlock();
534}
535
536template <bool tActive>
538 lock_(lock)
539{
540 lock_.lock();
541}
542
543template <bool tActive>
545 lock_(lock)
546{
547 lock.lock();
548}
549
550template <bool tActive>
552{
553 lock_.unlock();
554}
555
557 lock_(&lock)
558{
559 ocean_assert(lock_ != nullptr);
560 lock_->lock();
561}
562
564{
565 if (lock_ != nullptr)
566 {
567 lock_->unlock();
568 }
569}
570
572{
573 return lock_;
574}
575
577{
578 ocean_assert(!isReleased() && "This TemporaryScopedLock object has been released before");
579
580 if (lock_ != nullptr)
581 {
582 lock_->unlock();
583 lock_ = nullptr;
584 }
585}
586
588{
589 ocean_assert(isReleased() && "This TemporaryScopedLock object must be released before");
590
591 if (lock_ == nullptr)
592 {
593 lock_ = &lock;
594 lock_->lock();
595 }
596}
597
599{
600 return lock_ == nullptr;
601}
602
604 lock_(lock)
605{
606 if (lock_ != nullptr)
607 {
608 lock_->lock();
609 }
610}
611
612inline OptionalScopedLock::OptionalScopedLock(Lock& lock, const bool apply) :
613 lock_(nullptr)
614{
615 if (apply)
616 {
617 lock_ = &lock;
618 lock_->lock();
619 }
620}
621
623{
624 if (lock_ != nullptr)
625 {
626 lock_->unlock();
627 }
628}
629
631{
632 return lock_;
633}
634
635template <typename TScopedLock, typename TLock>
637 scopedLockFirst_(&lockA < &lockB ? lockA : lockB),
638 scopedLockSecond_(&lockA < &lockB ? lockB : lockA)
639{
640 // nothing to do here
641}
642
643}
644
645#endif // META_OCEAN_BASE_LOCK_H
This class implements a scoped lock object that locks two lock objects in a deterministic order based...
Definition Lock.h:341
TScopedLock scopedLockFirst_
Scopedlock object holding a lock on the lock with the lowest memory address.
Definition Lock.h:375
DualScopedLockT(TLock &lockA, TLock &lockB)
Creates a new dual scoped lock object based on two given lock objects.
Definition Lock.h:636
DualScopedLockT & operator=(const DualScopedLockT< TScopedLock, TLock > &object)=delete
Disabled accessible assigns operator.
~DualScopedLockT()=default
Destructs the dual scoped lock and unlocks both internal lock objects in reverse order.
DualScopedLockT(const DualScopedLockT< TScopedLock, TLock > &object)=delete
Disabled accessible copy operator.
TScopedLock scopedLockSecond_
Scoped lock object holding a lock on the lock with the highest memory address.
Definition Lock.h:378
This class implements a recursive lock object.
Definition Lock.h:31
CRITICAL_SECTION criticalSection_
Critical section object of windows.
Definition Lock.h:80
void lock()
Locks the critical section.
Definition Lock.h:473
~Lock()
Destructs a lock object.
Definition Lock.h:457
bool isLocked()
Returns whether this critical section is locked by another thread.
Definition Lock.h:502
Lock & operator=(const Lock &lock)=delete
Disabled assign operator.
void unlock()
Unlocks the critical section.
Definition Lock.h:487
Lock(const Lock &lock)=delete
Disabled copy constructor.
Lock()
Creates a new lock object.
Definition Lock.h:435
pthread_mutex_t mutex_
Pthread mutex object.
Definition Lock.h:85
This class implements an optional recursive scoped lock object locking the lock object only if it's d...
Definition Lock.h:387
~OptionalScopedLock()
Destructs an optional scoped lock and unlocks the internal lock object if defined.
Definition Lock.h:622
Lock * lock() const
Returns the lock object which (if existing) is locked during the existence of this scoped lock object...
Definition Lock.h:630
OptionalScopedLock & operator=(const OptionalScopedLock &object)=delete
Disabled accessible assigns operator.
Lock * lock_
Lock object which is locked during the existence of this scoped lock object.
Definition Lock.h:432
OptionalScopedLock(Lock *lock)
Creates a new optional scoped lock object by a given lock object.
Definition Lock.h:603
OptionalScopedLock(const OptionalScopedLock &object)=delete
Disabled accessible copy operator.
This class implements a scoped lock object for recursive lock objects.
Definition Lock.h:147
~ScopedLock()
Destructs a scoped lock and unlocks the internal lock object.
Definition Lock.h:531
ScopedLock(const ScopedLock &object)=delete
Disabled accessible copy operator.
ScopedLock & operator=(const ScopedLock &object)=delete
Disabled accessible assigns operator.
ScopedLock(Lock &lock)
Creates a new scoped lock object by a given lock object.
Definition Lock.h:525
Lock & lock_
Lock object which is locked during the existence of this scoped lock object.
Definition Lock.h:179
TemplatedLock & operator=(const TemplatedLock &lock)=delete
Disabled assign operator.
TemplatedLock(const TemplatedLock &lock)=delete
Disabled copy constructor.
TemplatedLock()=default
Creates a new lock object.
This class implements a template-based recursive lock object.
Definition Lock.h:99
TemplatedLock()=default
Creates a new lock object.
TemplatedScopedLock(Lock &lock)
Creates a new scoped lock object by a given lock object.
Definition Lock.h:245
TemplatedScopedLock(TemplatedLock< false > &lock)
Creates a new scoped lock object by a given lock object.
Definition Lock.h:254
This class implements a recursive scoped lock object that is activated by a boolean template paramete...
Definition Lock.h:190
TemplatedScopedLock(Lock &lock)
Creates a new scoped lock object by a given lock object.
Definition Lock.h:537
TemplatedScopedLock & operator=(const TemplatedScopedLock< tActive > &object)=delete
Disabled accessible assigns operator.
TemplatedScopedLock(const TemplatedScopedLock< tActive > &object)=delete
Disabled accessible copy operator.
~TemplatedScopedLock()
Destructs a scoped lock and unlocks the internal lock object.
Definition Lock.h:551
Lock & lock_
Lock object which is locked during the existence of this scoped lock object.
Definition Lock.h:228
This class implements a recursive scoped lock object allowing to release the lock before the scoped o...
Definition Lock.h:266
void relock(Lock &lock)
Re-locks this scoped lock with a given lock.
Definition Lock.h:587
TemporaryScopedLock(const TemporaryScopedLock &object)=delete
Disabled accessible copy operator.
Lock * lock() const
Returns the lock object which (if existing) is locked during the existence of this scoped lock object...
Definition Lock.h:571
void release()
Explicitly releases the lock before the scoped lock object is released.
Definition Lock.h:576
TemporaryScopedLock()=default
Creates a new scoped lock object which is not locked yet.
Lock * lock_
Lock object which is locked during the existence of this scoped lock object.
Definition Lock.h:328
TemporaryScopedLock & operator=(const TemporaryScopedLock &object)=delete
Disabled accessible assigns operator.
bool isReleased() const
Returns whether this scoped lock is released already.
Definition Lock.h:598
~TemporaryScopedLock()
Destructs a scoped lock and unlocks the internal lock object (if still locked).
Definition Lock.h:563
The namespace covering the entire Ocean framework.
Definition Accessor.h:15