ALib C++ Library
Library Version: 2510 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
locks.cpp
1// #################################################################################################
2// ALib C++ Library
3//
4// Copyright 2013-2025 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6// #################################################################################################
7#include "alib_precompile.hpp"
8#if !defined(ALIB_C20_MODULES) || ((ALIB_C20_MODULES != 0) && (ALIB_C20_MODULES != 1))
9# error "Symbol ALIB_C20_MODULES has to be given to the compiler as either 0 or 1"
10#endif
11#if ALIB_C20_MODULES
12 module;
13#endif
14// ====================================== Global Fragment ======================================
15#include "alib/alib.inl"
16#if ALIB_DEBUG && !ALIB_STRINGS
17# include <format>
18#endif
19// =========================================== Module ==========================================
20#if ALIB_C20_MODULES
21 module ALib.Threads;
22 import ALib.Lang;
23# if ALIB_STRINGS
24 import ALib.Strings;
25# endif
26#else
27# include "ALib.Threads.H"
28# include "ALib.Strings.H"
29# include "ALib.Lang.H"
30#endif
31// ====================================== Implementation =======================================
32#if !ALIB_SINGLE_THREADED
33
34namespace alib { namespace threads {
35
36// #################################################################################################
37// Globals
38// #################################################################################################
39/// This global mutex is acquired by \alib-types, whenever data is written to either
40/// <c>std::cout</c> or <c>std::cerr</c>.
41/// This is, for example, acquired by function #alib::assert::Raise and by loggers of
42/// module \alib_alox
43/// that log to the console.
45
46// #################################################################################################
47// Debug-Versions of Lock-Types
48// #################################################################################################
49#if ALIB_DEBUG
51{
52 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
53
54 if ( !Dbg.WaitTimeLimit.IsZero() )
55 {
56 Ticks::Duration waitDuration= Dbg.WaitTimeLimit;
57 Ticks overallTimer;
58 Ticks waitTimer;
59 while (!mutex.try_lock_for( (waitDuration - waitTimer.Age()).Export() ) )
60 {
61 if ( waitTimer.Age() < waitDuration )
62 continue; // spurious wakeup
63
64 #if ALIB_STRINGS
65 NAString msg("Waiting to acquire a lock since "); msg << overallTimer.Age();
66 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
67 #else
68 std::string msg("Waiting to acquire a lock since ");
69 msg+= std::format("{}", overallTimer.Age().InAbsoluteMilliseconds());
70 msg+= " ms";
71 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg.c_str());
72 #endif
73
74 waitTimer.Reset();
75 }
76 }
77 else
78 mutex.lock();
79
80 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
81 Dbg.CntAcquirements++;
82 Dbg.AcqCI= ci;
83}
84
86{
87 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
88
89 if (!mutex.try_lock() )
90 return false;
91
92 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
93 Dbg.CntAcquirements++;
94 Dbg.AcqCI= ci;
95
96 return true;
97}
98
100{
101 Dbg.AssertOwned ( ALIB_CALLER, ci, "Not acquired" );
102 Dbg.AssertOwning( ALIB_CALLER, ci, "Acquired by a different thread");
103
104 Dbg.CntAcquirements--;
105 Dbg.RelCI= ci;
106 mutex.unlock();
107}
108#endif // ALIB_DEBUG
109
110// #################################################################################################
111// Class TimedLock
112// #################################################################################################
113#if !ALIB_DEBUG
114bool TimedLock::TryAcquireTimed( const Ticks::Duration& waitDuration )
115{
116 Ticks::Duration remainingDuration= waitDuration;
117 Ticks timer;
118 while (!mutex.try_lock_for( remainingDuration.Export() ) )
119 {
120 remainingDuration= waitDuration - timer.Age();
121 if ( remainingDuration.IsPositive() )
122 continue; // spurious wakeup
123 return false;
124 }
125 return true;
126}
127#else
128
130{
131 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
132
133 if ( !Dbg.WaitTimeLimit.IsZero() )
134 {
135 Ticks::Duration waitDuration= Dbg.WaitTimeLimit;
136 Ticks overallTimer;
137 Ticks waitTimer;
138 while (!mutex.try_lock_for( (waitDuration - waitTimer.Age()).Export() ) )
139 {
140 if ( waitTimer.Age() < waitDuration )
141 continue; // spurious wakeup
142
143 #if ALIB_STRINGS
144 NAString msg("Waiting to acquire a lock since "); msg << overallTimer.Age();
145 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
146 #else
147 std::string msg("Waiting to acquire a lock since ");
148 msg+= std::format("{}", overallTimer.Age().InAbsoluteMilliseconds());
149 msg+= " ms";
150 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg.c_str());
151 #endif
152
153 waitTimer.Reset();
154 }
155 }
156 else
157 mutex.lock();
158
159 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
160 Dbg.CntAcquirements++;
161 Dbg.AcqCI= ci;
162}
163
165{
166 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
167
168 if (!mutex.try_lock() )
169 return false;
170
171 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
172
173 Dbg.CntAcquirements++;
174 Dbg.AcqCI= ci;
175 return true;
176}
177
178bool TimedLock::TryAcquireTimed( const Ticks::Duration& waitDuration,
179 const CallerInfo& ci )
180{
181 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
182
183 Ticks::Duration remainingDuration= waitDuration;
184 Ticks timer;
185 while (!mutex.try_lock_for( remainingDuration.Export() ) )
186 {
187 remainingDuration= waitDuration - timer.Age();
188 if ( remainingDuration.IsPositive() )
189 continue; // spurious wakeup
190 return false;
191 }
192
193 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
194
195 Dbg.CntAcquirements++;
196 Dbg.AcqCI= ci;
197 return true;
198}
200{
201 Dbg.AssertOwned ( ALIB_CALLER, ci, "Not acquired" );
202 Dbg.AssertOwning( ALIB_CALLER, ci, "Acquired by a different thread");
203
204 Dbg.CntAcquirements--;
205 Dbg.RelCI= ci;
206 mutex.unlock();
207}
208#endif // ALIB_DEBUG
209
210#if ALIB_DEBUG
212{
213 if ( !Dbg.WaitTimeLimit.IsZero() )
214 {
215 Ticks::Duration waitDuration= Dbg.WaitTimeLimit;
216 Ticks overallTimer;
217 Ticks waitTimer;
218 while (!mutex.try_lock_for( (waitDuration - waitTimer.Age()).Export() ) )
219 {
220 if ( waitTimer.Age() < waitDuration )
221 continue; // spurious wakeup
222
223 #if ALIB_STRINGS
224 NAString msg("Waiting to acquire a lock since "); msg << overallTimer.Age();
225 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
226 #else
227 std::string msg("Waiting to acquire a lock since ");
228 msg+= std::format("{}", overallTimer.Age().InAbsoluteMilliseconds());
229 msg+= " ms";
230 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg.c_str());
231 #endif
232 waitTimer.Reset();
233 }
234 }
235 else
236 mutex.lock();
237
238 Dbg.AssertNotOwnedOrMe( ALIB_CALLER, ci, "Still owned after locking" );
239 Dbg.CntAcquirements++;
240 Dbg.AcqCI= ci;
241 if( Dbg.RecursionLimit != 0
242 && (Dbg.CntAcquirements % Dbg.RecursionLimit) == 0 ) {
243 #if ALIB_STRINGS
244 NAString msg; msg << Dbg.CntAcquirements << " recursive acquisitions."
245 " Warning limit can be adopted with field DbgRecursionWarningThreshold";
246 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
247 #else
248 std::string msg; msg+= std::format("{}", Dbg.CntAcquirements);
249 msg+=" recursive acquisitions."
250 " Warning limit can be adopted with field DbgRecursionWarningThreshold";
251 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg.c_str());
252 #endif
253 }
254}
255
257{
258 if (!mutex.try_lock() )
259 return false;
260
261 Dbg.AssertNotOwnedOrMe( ALIB_CALLER, ci, "Still owned after locking" );
262 Dbg.CntAcquirements++;
263 Dbg.AcqCI= ci;
264 if( Dbg.RecursionLimit != 0
265 && (Dbg.CntAcquirements % Dbg.RecursionLimit) == 0 ) {
266 #if ALIB_STRINGS
267 NAString msg; msg << Dbg.CntAcquirements << " recursive acquisitions."
268 " Warning limit can be adopted with field DbgRecursionWarningThreshold";
269 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
270 #else
271 std::string msg; msg+= std::format("{}", Dbg.CntAcquirements);
272 msg+=" recursive acquisitions."
273 " Warning limit can be adopted with field DbgRecursionWarningThreshold";
274 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg.c_str());
275 #endif
276 }
277 return true;
278}
279
281{
282 Dbg.AssertOwned ( ALIB_CALLER, ci, "Not acquired" );
283 Dbg.AssertOwning( ALIB_CALLER, ci, "Not owned");
284
285 Dbg.RelCI = ci;
286 if(--Dbg.CntAcquirements >= 0)
287 mutex.unlock();
288}
289#endif // ALIB_DEBUG
290
291#if !ALIB_DEBUG
292bool RecursiveTimedLock::TryAcquireTimed( const Ticks::Duration& waitDuration )
293{
294 Ticks::Duration remainingDuration= waitDuration;
295 Ticks timer;
296 while (!mutex.try_lock_for( remainingDuration.Export() ) )
297 {
298 remainingDuration= waitDuration - timer.Age();
299 if ( remainingDuration.IsPositive() )
300 continue; // spurious wakeup
301 return false;
302 }
303 return true;
304}
305#else
307{
308 if ( !Dbg.WaitTimeLimit.IsZero() )
309 {
310 Ticks::Duration waitDuration= Dbg.WaitTimeLimit;
311 Ticks overallTimer;
312 Ticks waitTimer;
313 while (!mutex.try_lock_for( (waitDuration - waitTimer.Age()).Export() ) )
314 {
315 if ( waitTimer.Age() < waitDuration )
316 continue; // spurious wakeup
317
318 #if ALIB_STRINGS
319 NAString msg("Waiting to acquire a lock since "); msg << overallTimer.Age();
320 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
321 #else
322 std::string msg("Waiting to acquire a lock since ");
323 msg+= std::format("{}", overallTimer.Age().InAbsoluteMilliseconds());
324 msg+= " ms";
325 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg.c_str());
326 #endif
327
328 waitTimer.Reset();
329 }
330 }
331 else
332 mutex.lock();
333
334 Dbg.AssertNotOwnedOrMe( ALIB_CALLER, ci, "Still owned after locking" );
335 Dbg.CntAcquirements++;
336 Dbg.AcqCI= ci;
337 if( Dbg.RecursionLimit != 0
338 && (Dbg.CntAcquirements % Dbg.RecursionLimit) == 0 ) {
339 #if ALIB_STRINGS
340 NAString msg; msg << Dbg.CntAcquirements << " recursive acquisitions."
341 " Warning limit can be adopted with field DbgRecursionWarningThreshold";
342 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
343 #else
344 std::string msg; msg+= std::format("{}", Dbg.CntAcquirements);
345 msg+=" recursive acquisitions."
346 " Warning limit can be adopted with field DbgRecursionWarningThreshold";
347 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg.c_str());
348 #endif
349 }
350}
351
353{
354 if (!mutex.try_lock() )
355 return false;
356
357 Dbg.AssertNotOwnedOrMe( ALIB_CALLER, ci, "Still owned after locking" );
358 Dbg.CntAcquirements++;
359 Dbg.AcqCI= ci;
360 if( Dbg.RecursionLimit != 0
361 && (Dbg.CntAcquirements % Dbg.RecursionLimit) == 0 ) {
362 #if ALIB_STRINGS
363 NAString msg; msg << Dbg.CntAcquirements << " recursive acquisitions."
364 " Warning limit can be adopted with field DbgRecursionWarningThreshold";
365 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
366 #else
367 std::string msg; msg+= std::format("{}", Dbg.CntAcquirements);
368 msg+=" recursive acquisitions."
369 " Warning limit can be adopted with field DbgRecursionWarningThreshold";
370 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg.c_str());
371 #endif
372 }
373 return true;
374}
375
376bool RecursiveTimedLock::TryAcquireTimed( const Ticks::Duration& waitDuration,
377 const CallerInfo& ci )
378{
379 Ticks::Duration remainingDuration= waitDuration;
380 Ticks timer;
381 while (!mutex.try_lock_for( remainingDuration.Export() ) )
382 {
383 remainingDuration= waitDuration - timer.Age();
384 if ( remainingDuration.IsPositive() )
385 continue; // spurious wakeup
386 return false;
387 }
388
389 Dbg.AssertNotOwnedOrMe( ALIB_CALLER, ci, "Still owned after locking" );
390 Dbg.CntAcquirements++;
391 Dbg.AcqCI= ci;
392 if( Dbg.RecursionLimit != 0
393 && (Dbg.CntAcquirements % Dbg.RecursionLimit) == 0 ) {
394 #if ALIB_STRINGS
395 NAString msg; msg << Dbg.CntAcquirements << " recursive acquisitions."
396 " Warning limit can be adopted with field DbgRecursionWarningThreshold";
397 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
398 #else
399 std::string msg; msg+= std::format("{}", Dbg.CntAcquirements);
400 msg+=" recursive acquisitions."
401 " Warning limit can be adopted with field DbgRecursionWarningThreshold";
402 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg.c_str());
403 #endif
404 }
405 return true;
406}
407
409{
410 Dbg.AssertOwned ( ALIB_CALLER, ci, "Not acquired" );
411 Dbg.AssertOwning( ALIB_CALLER, ci, "Not owned");
412
413 Dbg.CntAcquirements--;
414 Dbg.RelCI= ci;
415 mutex.unlock();
416}
417#endif // ALIB_DEBUG
418
419#if ALIB_DEBUG
421{
422 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
423
424 if ( !Dbg.WaitTimeLimit.IsZero() )
425 {
426 Ticks::Duration waitDuration= Dbg.WaitTimeLimit;
427 Ticks overallTimer;
428 Ticks waitTimer;
429 while (!mutex.try_lock_for( (waitDuration - waitTimer.Age()).Export() ) )
430 {
431 if ( waitTimer.Age() < waitDuration )
432 continue; // spurious wakeup
433
434 #if ALIB_STRINGS
435 NAString msg("Waiting to acquire a lock since "); msg << overallTimer.Age();
436 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
437 #else
438 std::string msg("Waiting to acquire a lock since ");
439 msg+= std::format("{}", overallTimer.Age().InAbsoluteMilliseconds());
440 msg+= " ms";
441 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg.c_str());
442 #endif
443
444 waitTimer.Reset();
445 }
446 }
447 else
448 mutex.lock();
449
450 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
451 Dbg.CntAcquirements++;
452 Dbg.AcqCI= ci;
453}
454
456{
457 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
458
459 if (!mutex.try_lock() )
460 return false;
461
462 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
463 Dbg.CntAcquirements++;
464 Dbg.AcqCI= ci;
465 return true;
466}
467
469{
470 Dbg.AssertOwned ( ALIB_CALLER, ci, "Not acquired" );
471 Dbg.AssertOwning( ALIB_CALLER, ci, "Not owned");
472
473 Dbg.CntAcquirements--;
474 Dbg.RelCI= ci;
475 mutex.unlock();
476}
477
479{
480 Dbg.AssertNotOwning( ALIB_CALLER, ci,
481 "AcquireShared while already owning. (This is not allowed with std::shared_lock)" );
482
483 if ( !Dbg.WaitTimeLimit.IsZero() )
484 {
485 Ticks::Duration waitDuration= Dbg.WaitTimeLimit;
486 Ticks overallTimer;
487 Ticks waitTimer;
488 while (!mutex.try_lock_shared_for( (waitDuration - waitTimer.Age()).Export() ) )
489 {
490 if ( waitTimer.Age() < waitDuration )
491 continue; // spurious wakeup
492
493 #if ALIB_STRINGS
494 NAString msg("Waiting to acquire a lock since "); msg << overallTimer.Age();
495 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
496 #else
497 std::string msg("Waiting to acquire a lock since ");
498 msg+= std::format("{}", overallTimer.Age().InAbsoluteMilliseconds());
499 msg+= " ms";
500 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg.c_str());
501 #endif
502
503 waitTimer.Reset();
504 }
505 }
506 else
507 mutex.lock_shared();
508
509 if ( Dbg.CntSharedAcquirements.fetch_add(1) >= DbgWarningMaximumShared )
510 Dbg.DoAssert( 1, ALIB_CALLER, ci,
511 "Too many parallel shared acquisitions detected. "
512 "A reason might be that shared acquirers do not call ReleaseShared" );
513
514 Dbg.SAcqCI= ci;
515}
516
518{
519 Dbg.AssertNotOwning( ALIB_CALLER, ci,
520 "AcquireShared while already owning. (This is not allowed with std::shared_lock)" );
521
522 if ( !mutex.try_lock_shared() )
523 return false;
524
525
526 if ( Dbg.CntSharedAcquirements.fetch_add(1) >= DbgWarningMaximumShared )
527 Dbg.DoAssert( 1, ALIB_CALLER, ci,
528 "Too many parallel shared acquisitions detected. "
529 "A reason might be that shared acquirers do not call ReleaseShared" );
530
531 Dbg.SAcqCI= ci;
532 return true;
533}
534
536{
537 auto prevCounter= Dbg.CntSharedAcquirements.fetch_sub(1);
538 if ( prevCounter <= 0 )
539 Dbg.DoAssert( 0, ALIB_CALLER, ci,
540 "Too many invocations of ReleaseShared (from any thread) without prior acquisition" );
541
542 Dbg.SRelCI= ci;
543 mutex.unlock_shared();
544}
545#endif // ALIB_DEBUG
546
547#if !ALIB_DEBUG
548bool SharedTimedLock::TryAcquireTimed( const Ticks::Duration& waitDuration )
549{
550 Ticks::Duration remainingDuration= waitDuration;
551 Ticks timer;
552 while (!mutex.try_lock_for( remainingDuration.Export() ) )
553 {
554 remainingDuration= waitDuration - timer.Age();
555 if ( remainingDuration.IsPositive() )
556 continue; // spurious wakeup
557 return false;
558 }
559 return true;
560}
561#else
563{
564 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
565
566 if ( !Dbg.WaitTimeLimit.IsZero() )
567 {
568 Ticks::Duration waitDuration= Dbg.WaitTimeLimit;
569 Ticks overallTimer;
570 Ticks waitTimer;
571 while (!mutex.try_lock_for( (waitDuration - waitTimer.Age()).Export() ) )
572 {
573 if ( waitTimer.Age() < waitDuration )
574 continue; // spurious wakeup
575
576 #if ALIB_STRINGS
577 NAString msg("Waiting to acquire a lock since "); msg << overallTimer.Age();
578 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
579 #else
580 std::string msg("Waiting to acquire a lock since ");
581 msg+= std::format("{}", overallTimer.Age().InAbsoluteMilliseconds());
582 msg+= " ms";
583 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg.c_str());
584 #endif
585
586 waitTimer.Reset();
587 }
588 }
589 else
590 mutex.lock();
591
592 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
593 Dbg.CntAcquirements++;
594 Dbg.AcqCI= ci;
595}
597{
598 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
599
600 if (!mutex.try_lock() )
601 return false;
602
603 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
604 Dbg.CntAcquirements++;
605 Dbg.AcqCI= ci;
606 return true;
607}
608
609bool SharedTimedLock::TryAcquireTimed( const Ticks::Duration& waitDuration,
610 const CallerInfo& ci )
611{
612 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
613
614 Ticks::Duration remainingDuration= waitDuration;
615 Ticks timer;
616 while (!mutex.try_lock_for( remainingDuration.Export() ) )
617 {
618 remainingDuration= waitDuration - timer.Age();
619 if ( remainingDuration.IsPositive() )
620 continue; // spurious wakeup
621 return false;
622 }
623
624 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
625 Dbg.CntAcquirements++;
626 Dbg.AcqCI= ci;
627 return true;
628}
629
631{
632 Dbg.AssertOwned ( ALIB_CALLER, ci, "Not acquired" );
633 Dbg.AssertOwning( ALIB_CALLER, ci, "Not owned");
634
635 Dbg.CntAcquirements--;
636 Dbg.RelCI= ci;
637 mutex.unlock();
638}
639#endif
640
641#if !ALIB_DEBUG
642bool SharedTimedLock::TryAcquireSharedTimed( const Ticks::Duration& waitDuration )
643{
644 Ticks::Duration remainingDuration= waitDuration;
645 Ticks timer;
646 while (!mutex.try_lock_shared_for( remainingDuration.Export() ) )
647 {
648 remainingDuration= waitDuration - timer.Age();
649 if ( remainingDuration.IsPositive() )
650 continue; // spurious wakeup
651 return false;
652 }
653 return true;
654}
655
656#else
657
659{
660 Dbg.AssertNotOwning( ALIB_CALLER, ci,
661 "AcquireShared while already owning. (This is not allowed with std::shared_lock)" );
662
663 if ( !Dbg.WaitTimeLimit.IsZero() )
664 {
665 Ticks::Duration waitDuration= Dbg.WaitTimeLimit;
666 Ticks overallTimer;
667 Ticks waitTimer;
668 while (!mutex.try_lock_shared_for( (waitDuration - waitTimer.Age()).Export() ) )
669 {
670 if ( waitTimer.Age() < waitDuration )
671 continue; // spurious wakeup
672
673 #if ALIB_STRINGS
674 NAString msg("Waiting to acquire a lock since "); msg << overallTimer.Age();
675 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
676 #else
677 std::string msg("Waiting to acquire a lock since ");
678 msg+= std::format("{}", overallTimer.Age().InAbsoluteMilliseconds());
679 msg+= " ms";
680 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg.c_str());
681 #endif
682
683 waitTimer.Reset();
684 }
685 }
686 else
687 mutex.lock_shared();
688
689 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
690
691 if ( Dbg.CntSharedAcquirements.fetch_add(1) >= DbgWarningMaximumShared )
692 Dbg.DoAssert( 1, ALIB_CALLER, ci,
693 "Too many parallel shared acquisitions detected. "
694 "A reason might be that shared acquirers do not call ReleaseShared" );
695
696 Dbg.SAcqCI= ci;
697}
698
700{
701 Dbg.AssertNotOwning( ALIB_CALLER, ci,
702 "AcquireShared while already owning. (This is not allowed with std::shared_lock)" );
703
704 if ( !mutex.try_lock_shared() )
705 return false;
706
707 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
708
709 if ( Dbg.CntSharedAcquirements.fetch_add(1) >= DbgWarningMaximumShared )
710 Dbg.DoAssert( 1, ALIB_CALLER, ci,
711 "Too many parallel shared acquisitions detected. "
712 "A reason might be that shared acquirers do not call ReleaseShared" );
713
714 Dbg.SAcqCI= ci;
715 return true;
716}
717
718bool SharedTimedLock::TryAcquireSharedTimed( const Ticks::Duration& waitDuration,
719 const CallerInfo& ci )
720{
721 Dbg.AssertNotOwning( ALIB_CALLER, ci,
722 "AcquireShared while already owning. (This is not allowed with std::shared_lock)" );
723
724 Ticks::Duration remainingDuration= waitDuration;
725 Ticks timer;
726 while (!mutex.try_lock_shared_for( remainingDuration.Export() ) )
727 {
728 remainingDuration= waitDuration - timer.Age();
729 if ( remainingDuration.IsPositive() )
730 continue; // spurious wakeup
731 return false;
732 }
733
734 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
735
736 if ( Dbg.CntSharedAcquirements.fetch_add(1) >= DbgWarningMaximumShared )
737 Dbg.DoAssert( 1, ALIB_CALLER, ci,
738 "Too many parallel shared acquisitions detected. "
739 "A reason might be that shared acquirers do not call ReleaseShared" );
740
741 Dbg.SAcqCI= ci;
742 return true;
743}
744
746{
747 auto prevCounter= Dbg.CntSharedAcquirements.fetch_sub(1);
748 if ( prevCounter <= 0 )
749 Dbg.DoAssert( 0, ALIB_CALLER, ci,
750 "Too many invocations of ReleaseShared (from any thread) without prior acquisition" );
751
752 Dbg.SRelCI= ci;
753 mutex.unlock_shared();
754}
755
756#endif // ALIB_DEBUG
757
758#if ALIB_DEBUG_CRITICAL_SECTIONS
759bool Lock ::DCSIsAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
760bool Lock ::DCSIsSharedAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
761bool TimedLock ::DCSIsAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
762bool TimedLock ::DCSIsSharedAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
763bool RecursiveLock ::DCSIsAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
764bool RecursiveLock ::DCSIsSharedAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
765bool RecursiveTimedLock::DCSIsAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
766bool RecursiveTimedLock::DCSIsSharedAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
767bool SharedLock ::DCSIsAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
768bool SharedLock ::DCSIsSharedAcquired() const { return Dbg.IsSharedOwnedByAnyThread()
769 || Dbg.IsOwnedByCurrentThread(); }
770bool SharedTimedLock ::DCSIsAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
771bool SharedTimedLock ::DCSIsSharedAcquired() const { return Dbg.IsSharedOwnedByAnyThread()
772 || Dbg.IsOwnedByCurrentThread(); }
773#endif // ALIB_DEBUG_CRITICAL_SECTIONS
774
775}} // namespace [alib::threads]
776
777#endif // !ALIB_SINGLE_THREADED
DbgLockAsserter Dbg
The debug tool instance.
Definition lock.inl:65
std::mutex mutex
Definition lock.inl:58
ALIB_DLL void Release(ALIB_DBG_TAKE_CI)
Definition locks.cpp:99
ALIB_DLL bool TryAcquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:85
ALIB_DLL void Acquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:50
ALIB_DLL void AcquireRecursive(ALIB_DBG_TAKE_CI)
Definition locks.cpp:211
std::recursive_mutex mutex
ALIB_DLL void ReleaseRecursive(ALIB_DBG_TAKE_CI)
Definition locks.cpp:280
ALIB_DLL bool TryAcquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:256
DbgLockAsserter Dbg
The debug tool instance.
ALIB_DLL void ReleaseRecursive(ALIB_DBG_TAKE_CI)
Definition locks.cpp:408
DbgLockAsserter Dbg
The debug tool instance.
virtual ALIB_DLL bool DCSIsAcquired() const override
Definition locks.cpp:765
std::recursive_timed_mutex mutex
The internal object to lock on.
virtual ALIB_DLL bool DCSIsSharedAcquired() const override
Definition locks.cpp:766
ALIB_DLL bool TryAcquireTimed(const Ticks::Duration &waitDuration, const CallerInfo &ci)
Definition locks.cpp:376
ALIB_DLL void AcquireRecursive(ALIB_DBG_TAKE_CI)
Definition locks.cpp:306
ALIB_DLL bool TryAcquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:352
ALIB_DLL bool TryAcquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:455
std::atomic< int > DbgWarningMaximumShared
ALIB_DLL void Release(ALIB_DBG_TAKE_CI)
Definition locks.cpp:468
std::shared_mutex mutex
DbgSharedLockAsserter Dbg
The debug tool instance.
ALIB_DLL void ReleaseShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:535
ALIB_DLL void AcquireShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:478
ALIB_DLL bool TryAcquireShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:517
ALIB_DLL void Acquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:420
DbgSharedLockAsserter Dbg
The debug tool instance.
std::shared_timed_mutex mutex
The internal object to lock on.
ALIB_DLL void AcquireShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:658
ALIB_DLL void Acquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:562
ALIB_DLL bool TryAcquireShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:699
std::atomic< int > DbgWarningMaximumShared
ALIB_DLL void ReleaseShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:745
ALIB_DLL bool TryAcquireTimed(const Ticks::Duration &waitDuration, const CallerInfo &ci)
Definition locks.cpp:609
ALIB_DLL bool TryAcquireSharedTimed(const Ticks::Duration &waitDuration, const CallerInfo &ci)
Definition locks.cpp:718
ALIB_DLL void Release(ALIB_DBG_TAKE_CI)
Definition locks.cpp:630
ALIB_DLL bool TryAcquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:596
DbgLockAsserter Dbg
The debug tool instance.
Definition timedlock.inl:55
ALIB_DLL bool TryAcquireTimed(const Ticks::Duration &waitDuration, const CallerInfo &ci)
Definition locks.cpp:178
ALIB_DLL void Release(ALIB_DBG_TAKE_CI)
Definition locks.cpp:199
std::timed_mutex mutex
The internal object to lock on.
Definition timedlock.inl:50
ALIB_DLL bool TryAcquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:164
ALIB_DLL void Acquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:129
#define ALIB_DBG_TAKE_CI
Definition alib.inl:1013
#define ALIB_CALLER
Definition alib.inl:1001
ALIB_DLL Lock STD_IOSTREAMS_LOCK
Definition locks.cpp:44
strings::TAString< nchar, lang::HeapAllocator > NAString
Type alias in namespace alib.
lang::CallerInfo CallerInfo
Type alias in namespace alib.
time::Ticks Ticks
Type alias in namespace alib.
Definition ticks.inl:109