CppCommon  1.0.4.1
C++ Common Library
critical_section.cpp
Go to the documentation of this file.
1 
10 
11 #include "threads/thread.h"
13 
14 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
15 #include "errors/fatal.h"
16 #include <pthread.h>
17 #elif defined(_WIN32) || defined(_WIN64)
18 #include <windows.h>
19 #undef Yield
20 #endif
21 
22 namespace CppCommon {
23 
25 
26 class CriticalSection::Impl
27 {
28 public:
29  Impl()
30  {
31 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
32  pthread_mutexattr_t mutex_attribute;
33  int result = pthread_mutexattr_init(&mutex_attribute);
34  if (result != 0)
35  throwex SystemException("Failed to initialize a mutex attribute!", result);
36  result = pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
37  if (result != 0)
38  throwex SystemException("Failed to set a mutex recursive attribute!", result);
39  result = pthread_mutex_init(&_lock, &mutex_attribute);
40  if (result != 0)
41  throwex SystemException("Failed to initialize a mutex!", result);
42  result = pthread_mutexattr_destroy(&mutex_attribute);
43  if (result != 0)
44  throwex SystemException("Failed to destroy a mutex attribute!", result);
45 #elif defined(_WIN32) || defined(_WIN64)
46  InitializeCriticalSection(&_lock);
47 #endif
48  }
49 
50  ~Impl()
51  {
52 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
53  int result = pthread_mutex_destroy(&_lock);
54  if (result != 0)
55  fatality(SystemException("Failed to destroy a mutex!", result));
56 #elif defined(_WIN32) || defined(_WIN64)
57  DeleteCriticalSection(&_lock);
58 #endif
59  }
60 
61  void* native() noexcept
62  {
63  return &_lock;
64  }
65 
66  bool TryLock()
67  {
68 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
69  int result = pthread_mutex_trylock(&_lock);
70  if ((result != 0) && (result != EAGAIN) && (result != EBUSY) && (result != EDEADLK))
71  throwex SystemException("Failed to try lock a mutex!", result);
72  return (result == 0);
73 #elif defined(_WIN32) || defined(_WIN64)
74  return (TryEnterCriticalSection(&_lock) != 0);
75 #endif
76  }
77 
78  void Lock()
79  {
80 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
81  int result = pthread_mutex_lock(&_lock);
82  if (result != 0)
83  throwex SystemException("Failed to lock a mutex!", result);
84 #elif defined(_WIN32) || defined(_WIN64)
85  EnterCriticalSection(&_lock);
86 #endif
87  }
88 
89  void Unlock()
90  {
91 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
92  int result = pthread_mutex_unlock(&_lock);
93  if (result != 0)
94  throwex SystemException("Failed to unlock a mutex!", result);
95 #elif defined(_WIN32) || defined(_WIN64)
96  LeaveCriticalSection(&_lock);
97 #endif
98  }
99 
100 private:
101 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
102  pthread_mutex_t _lock;
103 #elif defined(_WIN32) || defined(_WIN64)
104  CRITICAL_SECTION _lock;
105 #endif
106 };
107 
109 
111 {
112  // Check implementation storage parameters
113  [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
114  static_assert((StorageSize >= sizeof(Impl)), "CriticalSection::StorageSize must be increased!");
115  static_assert(((StorageAlign % alignof(Impl)) == 0), "CriticalSection::StorageAlign must be adjusted!");
116 
117  // Create the implementation instance
118  new(&_storage)Impl();
119 }
120 
122 {
123  // Delete the implementation instance
124  reinterpret_cast<Impl*>(&_storage)->~Impl();
125 }
126 
127 void* CriticalSection::native() noexcept { return impl().native(); }
128 
129 bool CriticalSection::TryLock() { return impl().TryLock(); }
130 
132 {
133  // Calculate a finish timestamp
134  Timestamp finish = NanoTimestamp() + timespan;
135 
136  // Try to acquire critical section at least one time
137  if (TryLock())
138  return true;
139  else
140  {
141  // Try lock or yield for the given timespan
142  while (NanoTimestamp() < finish)
143  {
144  if (TryLock())
145  return true;
146  else
147  Thread::Yield();
148  }
149 
150  // Failed to acquire critical section
151  return false;
152  }
153 }
154 
155 void CriticalSection::Lock() { impl().Lock(); }
156 void CriticalSection::Unlock() { impl().Unlock(); }
157 
158 } // namespace CppCommon
bool TryLock()
Try to acquire critical section without block.
void Lock()
Acquire critical section with block.
bool TryLockFor(const Timespan &timespan)
Try to acquire critical section for the given timespan.
void Unlock()
Release critical section.
High resolution timestamp.
Definition: timestamp.h:272
static void Yield() noexcept
Yield to other threads.
Definition: thread.cpp:143
Critical section synchronization primitive definition.
#define throwex
Throw extended exception macro.
Definition: exceptions.h:23
Fatal abort execution definition.
#define fatality(...)
Fatal abort execution extended macro.
Definition: fatal.h:22
C++ Common project definitions.
Definition: token_bucket.h:15
Thread definition.
Aligned storage validator definition.