Coverage Report

Created: 2026-04-29 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/poco/Foundation/include/Poco/Mutex.h
Line
Count
Source
1
//
2
// Mutex.h
3
//
4
// Library: Foundation
5
// Package: Threading
6
// Module:  Mutex
7
//
8
// Definition of the Mutex and FastMutex classes.
9
//
10
// Copyright (c) 2004-2008, Applied Informatics Software Engineering GmbH.
11
// and Contributors.
12
//
13
// SPDX-License-Identifier: BSL-1.0
14
//
15
16
17
#ifndef Foundation_Mutex_INCLUDED
18
#define Foundation_Mutex_INCLUDED
19
20
21
#include "Poco/Foundation.h"
22
#include "Poco/Exception.h"
23
#include "Poco/ScopedLock.h"
24
#include "Poco/Timestamp.h"
25
#include <atomic>
26
#include <thread>
27
28
#ifdef POCO_ENABLE_STD_MUTEX
29
#include "Poco/Mutex_STD.h"
30
#else
31
#if defined(POCO_OS_FAMILY_WINDOWS)
32
#include "Poco/Mutex_WIN32.h"
33
#elif defined(POCO_VXWORKS)
34
#include "Poco/Mutex_VX.h"
35
#else
36
#include "Poco/Mutex_POSIX.h"
37
#endif
38
#endif
39
40
41
namespace Poco {
42
43
44
class Foundation_API Mutex: private MutexImpl
45
  /// A Mutex (mutual exclusion) is a synchronization
46
  /// mechanism used to control access to a shared resource
47
  /// in a concurrent (multithreaded) scenario.
48
  /// Mutexes are recursive, that is, the same mutex can be
49
  /// locked multiple times by the same thread (but, of course,
50
  /// not by other threads).
51
  /// Using the ScopedLock class is the preferred way to automatically
52
  /// lock and unlock a mutex.
53
{
54
public:
55
  using ScopedLock = Poco::ScopedLock<Mutex>;
56
  using ScopedLockWithUnlock = Poco::ScopedLockWithUnlock<Mutex>;
57
58
  Mutex();
59
    /// creates the Mutex.
60
61
  ~Mutex();
62
    /// destroys the Mutex.
63
64
  void lock();
65
    /// Locks the mutex. Blocks if the mutex
66
    /// is held by another thread.
67
68
  void lock(long milliseconds);
69
    /// Locks the mutex. Blocks up to the given number of milliseconds
70
    /// if the mutex is held by another thread. Throws a TimeoutException
71
    /// if the mutex can not be locked within the given timeout.
72
    ///
73
    /// Performance Note: On most platforms (including Windows), this member function is
74
    /// implemented using a loop calling (the equivalent of) tryLock() and Thread::sleep().
75
    /// On POSIX platforms that support pthread_mutex_timedlock(), this is used.
76
77
  bool tryLock();
78
    /// Tries to lock the mutex. Returns false immediately
79
    /// if the mutex is already held by another thread.
80
    /// Returns true if the mutex was successfully locked.
81
82
  bool tryLock(long milliseconds);
83
    /// Locks the mutex. Blocks up to the given number of milliseconds
84
    /// if the mutex is held by another thread.
85
    /// Returns true if the mutex was successfully locked.
86
    ///
87
    /// Performance Note: On most platforms (including Windows), this member function is
88
    /// implemented using a loop calling (the equivalent of) tryLock() and Thread::sleep().
89
    /// On POSIX platforms that support pthread_mutex_timedlock(), this is used.
90
91
  void unlock();
92
    /// Unlocks the mutex so that it can be acquired by
93
    /// other threads.
94
95
private:
96
  Mutex(const Mutex&);
97
  Mutex& operator = (const Mutex&);
98
};
99
100
101
class Foundation_API FastMutex: private FastMutexImpl
102
  /// A FastMutex (mutual exclusion) is similar to a Mutex.
103
  /// Unlike a Mutex, however, a FastMutex is not recursive,
104
  /// which means that a deadlock will occur if the same
105
  /// thread tries to lock a mutex it has already locked again.
106
  /// Locking a FastMutex is faster than locking a recursive Mutex.
107
  /// Using the ScopedLock class is the preferred way to automatically
108
  /// lock and unlock a mutex.
109
{
110
public:
111
  using ScopedLock = Poco::ScopedLock<FastMutex>;
112
  using ScopedLockWithUnlock = Poco::ScopedLockWithUnlock<FastMutex>;
113
114
  FastMutex();
115
    /// creates the Mutex.
116
117
  ~FastMutex();
118
    /// destroys the Mutex.
119
120
  void lock();
121
    /// Locks the mutex. Blocks if the mutex
122
    /// is held by another thread.
123
124
  void lock(long milliseconds);
125
    /// Locks the mutex. Blocks up to the given number of milliseconds
126
    /// if the mutex is held by another thread. Throws a TimeoutException
127
    /// if the mutex can not be locked within the given timeout.
128
    ///
129
    /// Performance Note: On most platforms (including Windows), this member function is
130
    /// implemented using a loop calling (the equivalent of) tryLock() and Thread::sleep().
131
    /// On POSIX platforms that support pthread_mutex_timedlock(), this is used.
132
133
  bool tryLock();
134
    /// Tries to lock the mutex. Returns false immediately
135
    /// if the mutex is already held by another thread.
136
    /// Returns true if the mutex was successfully locked.
137
138
  bool tryLock(long milliseconds);
139
    /// Locks the mutex. Blocks up to the given number of milliseconds
140
    /// if the mutex is held by another thread.
141
    /// Returns true if the mutex was successfully locked.
142
    ///
143
    /// Performance Note: On most platforms (including Windows), this member function is
144
    /// implemented using a loop calling (the equivalent of) tryLock() and Thread::sleep().
145
    /// On POSIX platforms that support pthread_mutex_timedlock(), this is used.
146
147
  void unlock();
148
    /// Unlocks the mutex so that it can be acquired by
149
    /// other threads.
150
151
private:
152
  FastMutex(const FastMutex&);
153
  FastMutex& operator = (const FastMutex&);
154
};
155
156
157
class Foundation_API SpinlockMutex
158
  /// A SpinlockMutex, implemented in terms of std::atomic_flag, as
159
  /// busy-wait mutual exclusion.
160
  ///
161
  /// Spins adaptively: spin briefly, then yield, then sleep.
162
  /// This avoids burning CPU while still being fast for uncontended locks.
163
  /// On C++20, uses test() with relaxed ordering for efficient polling
164
  /// (avoids cache line bouncing), then test_and_set() with acquire
165
  /// only when the lock appears free.
166
  ///
167
  /// While in some cases (eg. locking small blocks of code)
168
  /// busy-waiting may be an optimal solution, in many scenarios
169
  /// spinlock may not be the right choice (especially on single-core
170
  /// systems) - it is up to the user to choose the proper mutex type
171
  /// for their particular case.
172
  ///
173
  /// Works with the ScopedLock class.
174
{
175
public:
176
  using ScopedLock = Poco::ScopedLock<SpinlockMutex>;
177
  using ScopedLockWithUnlock = Poco::ScopedLockWithUnlock<SpinlockMutex>;
178
179
  SpinlockMutex();
180
    /// Creates the SpinlockMutex.
181
182
  ~SpinlockMutex();
183
    /// Destroys the SpinlockMutex.
184
185
  void lock();
186
    /// Locks the mutex. Blocks if the mutex
187
    /// is held by another thread.
188
189
  void lock(long milliseconds);
190
    /// Locks the mutex. Blocks up to the given number of milliseconds
191
    /// if the mutex is held by another thread. Throws a TimeoutException
192
    /// if the mutex can not be locked within the given timeout.
193
194
  bool tryLock();
195
    /// Tries to lock the mutex. Returns immediately, false
196
    /// if the mutex is already held by another thread, true
197
    /// if the mutex was successfully locked.
198
199
  bool tryLock(long milliseconds);
200
    /// Locks the mutex. Blocks up to the given number of milliseconds
201
    /// if the mutex is held by another thread.
202
    /// Returns true if the mutex was successfully locked.
203
204
  void unlock();
205
    /// Unlocks the mutex so that it can be acquired by
206
    /// other threads.
207
208
private:
209
  std::atomic_flag _flag = ATOMIC_FLAG_INIT;
210
};
211
212
213
class Foundation_API NullMutex
214
  /// A NullMutex is an empty mutex implementation
215
  /// which performs no locking at all. Useful in policy driven design
216
  /// where the type of mutex used can be now a template parameter allowing the user to switch
217
  /// between thread-safe and not thread-safe depending on his need
218
  /// Works with the ScopedLock class
219
{
220
public:
221
  using ScopedLock = Poco::ScopedLock<NullMutex>;
222
  using ScopedLockWithUnlock = Poco::ScopedLockWithUnlock<NullMutex>;
223
224
  NullMutex() = default;
225
    /// Creates the NullMutex.
226
227
  ~NullMutex() = default;
228
    /// Destroys the NullMutex.
229
230
  void lock()
231
    /// Does nothing.
232
0
  {
233
0
  }
234
235
  void lock(long)
236
    /// Does nothing.
237
0
  {
238
0
  }
239
240
  bool tryLock()
241
    /// Does nothing and always returns true.
242
0
  {
243
0
    return true;
244
0
  }
245
246
  bool tryLock(long)
247
    /// Does nothing and always returns true.
248
0
  {
249
0
    return true;
250
0
  }
251
252
  void unlock()
253
    /// Does nothing.
254
0
  {
255
0
  }
256
};
257
258
259
//
260
// inlines
261
//
262
263
//
264
// Mutex
265
//
266
267
inline void Mutex::lock()
268
0
{
269
0
  lockImpl();
270
0
}
271
272
273
inline void Mutex::lock(long milliseconds)
274
0
{
275
0
  if (!tryLockImpl(milliseconds))
276
0
    throw TimeoutException();
277
0
}
278
279
280
inline bool Mutex::tryLock()
281
0
{
282
0
  return tryLockImpl();
283
0
}
284
285
286
inline bool Mutex::tryLock(long milliseconds)
287
0
{
288
0
  return tryLockImpl(milliseconds);
289
0
}
290
291
292
inline void Mutex::unlock()
293
0
{
294
0
  unlockImpl();
295
0
}
296
297
298
//
299
// FastMutex
300
//
301
302
inline void FastMutex::lock()
303
503k
{
304
503k
  lockImpl();
305
503k
}
306
307
308
inline void FastMutex::lock(long milliseconds)
309
0
{
310
0
  if (!tryLockImpl(milliseconds))
311
0
    throw TimeoutException();
312
0
}
313
314
315
inline bool FastMutex::tryLock()
316
0
{
317
0
  return tryLockImpl();
318
0
}
319
320
321
inline bool FastMutex::tryLock(long milliseconds)
322
0
{
323
0
  return tryLockImpl(milliseconds);
324
0
}
325
326
327
inline void FastMutex::unlock()
328
503k
{
329
503k
  unlockImpl();
330
503k
}
331
332
333
//
334
// SpinlockMutex
335
//
336
337
338
inline bool SpinlockMutex::tryLock()
339
0
{
340
0
  return !_flag.test_and_set(std::memory_order_acquire);
341
0
}
342
343
344
inline void SpinlockMutex::unlock()
345
0
{
346
0
  _flag.clear(std::memory_order_release);
347
0
}
348
349
350
} // namespace Poco
351
352
353
#endif // Foundation_Mutex_INCLUDED