ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
locks.cpp
1// #################################################################################################
2// ALib C++ Library
3//
4// Copyright 2013-2024 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6// #################################################################################################
8
9#if !DOXYGEN
10# include "alib/threads/lock.hpp"
18#endif // !DOXYGEN
19
20#if ALIB_MONOMEM
22#endif
23#include "alib/time/ticks.hpp"
24#if ALIB_DEBUG
26#endif
27#if ALIB_CAMP
30#endif
31#if ALIB_ALOX
32# include "alib/alox.hpp"
34#endif
35
36
37namespace alib { namespace threads {
38
39// #################################################################################################
40// Class DbgLockAsserter
41// #################################################################################################
42#if ALIB_DEBUG
44{
45 if ( CntAcquirements == 0 )
46 return nullptr;
48}
49
50#if ALIB_CAMP && !DOXYGEN // otherwise doxygen will write a bad version of the initial value
52"Multi-Threadding {} in Lock {!Q}" "\n"
53" Message: {}" "\n"
54" In (Member-)Function: {:ya}" "\n"
55" Is Owned: {7}" "\n"
56 "\n"
57" Called By: {4:ya}" "\n"
58" At: {4:sf:sl}" "\n"
59" Thread: {4:ta}" "\n"
60 "\n"
61" Latest Acquisition By: {5:ya}" "\n"
62" At: {5:sf:sl}" "\n"
63" Thread: {5:ta}" "\n"
64" Latest Release By: {6:ya}" "\n"
65" At: {6:sf:sl}" "\n"
66" Thread: {6:ta}" "\n"
67;
68
70"Multi-Threadding {} in Lock {!Q}" "\n"
71" Message: {}" "\n"
72" In (Member-)Function: {:ya}" "\n"
73" Is Owned: {7}" "\n"
74" Is Shared Owned: {10}" "\n"
75 "\n"
76" Called By: {4:ya}" "\n"
77" At: {4:sf:sl}" "\n"
78" Thread: {4:ta}" "\n"
79 "\n"
80" Latest Acquisition By: {5:ya}" "\n"
81" At: {5:sf:sl}" "\n"
82" Thread: {5:ta}" "\n"
83" Latest Release By: {6:ya}" "\n"
84" At: {6:sf:sl}" "\n"
85" Thread: {6:ta}" "\n"
86 "\n"
87" Latest Shared Acquisition By: {8:ya}" "\n"
88" At: {8:sf:sl}" "\n"
89" Thread: {8:ta}" "\n"
90" Latest SharedRelease By: {9:ya}" "\n"
91" At: {9:sf:sl}" "\n"
92" Thread: {9:ta}" "\n"
93;
94#endif // ALIB_CAMP && !DOXYGEN
95
96
97void DbgLockAsserter::DoAssert( int type, const CallerInfo& ciAssert, const CallerInfo& ci,
98 const NString& headline )
99{
100 String4K msg;
101
102 #if !ALIB_CAMP
103 msg << (type== 0 ? "Assertion" : "Warning")
104 << " with Mutex/Locking in " << Name << "\n"
105 " Message: " << headline << "\n"
106 " Caller: " << ci << "\n"
107 " Is Owned: " << (CntAcquirements>0 ? "true" : "false") << " (" << CntAcquirements << ")\n"
108 " Latest Acquirement: " << AcqCI << "\n"
109 " Latest Release: " << RelCI << "\n\n"
110 "Note: Include ALib module BaseCamp in the ALib-Distribution to get nicer assertion output.\n";
111 #else
112 String256 acquirementInfo;
113 acquirementInfo << (CntAcquirements>0 ? "true" : "false") << " (" <<CntAcquirements<< ')';
114
116 fmt.Format( msg , ASSERTION_FORMAT,
117 (type== 0 ? "Assertion" : "Warning"), // 0
118 Name , headline, // 1 2
119 ciAssert, ci, // 3 4
120 AcqCI , RelCI, // 5 6
121 acquirementInfo ); // 7
122
123 #endif
124 #if ALIB_ALOX
125 int oldMode= 1;
126 if ( Log::DebugLogger )
127 {
130 }
131 #endif
132
133 ALIB_STRINGS_TO_NARROW(msg, nmsg, 8192) // needs to be quite big for max conversions
134 DbgSimpleALibMsg( ciAssert, type, "THREADS", nmsg );
135
136 #if ALIB_ALOX
137 if ( Log::DebugLogger )
139 #endif
140 }
141
142void DbgSharedLockAsserter::DoAssert( int type, const CallerInfo& ciAssert, const CallerInfo& ci,
143 const NString& headline )
144{
145 String4K msg;
146
147 #if !ALIB_CAMP
148 msg << (type== 0 ? "Assertion" : "Warning")
149 << " with Mutex/Locking in " << Name << "\n"
150 " Message: " << headline << "\n"
151 " Caller: " << ci << "\n"
152 " Is Owned: " << (CntAcquirements>0 ? "true " : "false") << " (" << CntAcquirements << ")\n"
153 " Is Shared-Owned: " << (CntSharedAcquirements.load()>0 ? "true " : "false") << " (" << CntSharedAcquirements.load() << ")\n\n"
154 " Latest Acquirement: " << AcqCI << "\n"
155 " Latest Release: " << RelCI << "\n\n"
156 " Latest Shared Acquirement: " << SAcqCI << "\n"
157 " Latest Shared Release: " << SRelCI << "\n\n"
158 "Note: Include ALib module BaseCamp in the ALib-Distribution to get nicer assertion output.\n";
159 #else
160 String256 acquirementInfo;
161 acquirementInfo << (CntAcquirements>0 ? "true " : "false") << " (" <<CntAcquirements<< ')';
162 String256 sharedAcquirementInfo;
163 sharedAcquirementInfo << (CntSharedAcquirements.load()>0 ? "true " : "false") << " (" <<CntSharedAcquirements.load()<< ')';
164
167 (type== 0 ? "Assertion" : "Warning"), // 0
168 Name , headline, // 1 2
169 ciAssert, ci, // 3 4
170 AcqCI , RelCI, acquirementInfo, // 5 6 7
171 SAcqCI ,SRelCI, sharedAcquirementInfo); // 8 9 10
172
173 #endif
174 #if ALIB_ALOX
175 int oldMode= 1;
176 if ( Log::DebugLogger )
177 {
180 }
181 #endif
182
183 ALIB_STRINGS_TO_NARROW(msg, nmsg, 4096)
184 DbgSimpleALibMsg( ciAssert, type, "THREADS", nmsg );
185
186 #if ALIB_ALOX
187 if ( Log::DebugLogger )
189 #endif
190
191 }
192
193#if ALIB_CAMP && !DOXYGEN // otherwise doxygen will write a bad version of the initial value
195"Assertion failed in method TCondition::{2:sm}" "\n"
196" Message: {0}" "\n"
197" Instance: {1}" "\n"
198 "\n"
199" Called By: {3:ya}" "\n"
200" At: {3:sf:sl}" "\n"
201" Thread: {3:ta}" "\n"
202 "\n"
203" Current Owner: {4}" "\n"
204" #Of Waiters: {5}" "\n"
205" Exclusive Waiter: {6}" "\n"
206 "\n"
207" Latest Acquisition By: {7:ya}" "\n"
208" At: {7:sf:sl}" "\n"
209" Thread: {7:ta}" "\n"
210" Latest Release By: {8:ya}" "\n"
211" At: {8:sf:sl}" "\n"
212" Thread: {8:ta}" "\n"
213 "\n"
214" Latest Wait By: {9:ya}" "\n"
215" At: {9:sf:sl}" "\n"
216" Thread: {9:ta}" "\n"
217" Latest Notify By: {10:ya}" "\n"
218" At: {10:sf:sl}" "\n"
219" Thread: {10:ta}" "\n"
220;
221#endif // ALIB_CAMP && !DOXYGEN
222
223void DbgConditionAsserter::Assert( bool cond, const CallerInfo& ciAssert, const CallerInfo& ci,
224 const NString& headline )
225{
226 if (cond )
227 return;
228 String4K msg;
229
230 #if !ALIB_CAMP
231 msg << "Assertion failed in method TCondition::" << ciAssert.Func << "()\n"
232 " Message: " << headline << "\n"
233 " Instance: " << Name << "(0x" << Format::Hex(reinterpret_cast<integer>(this)) << ")\n\n"
234 " Caller: " << ci << "\n\n"
235 " Current Owner: " << Owner << "\n"
236 " #Of Waiters: " << CntWaiters.load() << "\n"
237 " Exclusive Waiter: " << AssertExclusiveWaiter << "\n\n"
238 " Most Recent Acquirement: " << AcqCI << "\n"
239 " Most Recent Release: " << RelCI << "\n"
240 " Most Recent Wait: " << WaitCI << "\n"
241 " Most Recent Notify: " << NotifyCI << "\n"
242 "Note: Include ALib module BaseCamp in the ALib-Distribution to get nicer assertion output.\n";
243
244 #else
245 NString128 name; name << Name << "(0x" << NFormat::Hex(reinterpret_cast<integer>(this)) << ')';
247 fmt.Format( msg, ASSERTION_FORMAT,
248 headline, name, // 0 1
249 ciAssert, ci, // 2 3
250 Owner , CntWaiters.load(), AssertExclusiveWaiter, // 4 5 6
251 AcqCI , RelCI, WaitCI, NotifyCI ); // 7 8 9 10
252
253 #endif
254 #if ALIB_ALOX
255 int oldMode= 1;
256 if ( Log::DebugLogger )
257 {
260 }
261 #endif
262
263 ALIB_STRINGS_TO_NARROW(msg, nmsg, 4096)
264 DbgSimpleALibMsg( ciAssert, 0, "THREADS", nmsg );
265
266 #if ALIB_ALOX
267 if ( Log::DebugLogger )
269 #endif
270
271 }
272
273#if ALIB_DEBUG_CRITICAL_SECTIONS
274bool Lock ::DCSIsAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
275bool Lock ::DCSIsSharedAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
276bool TimedLock ::DCSIsAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
277bool TimedLock ::DCSIsSharedAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
278bool RecursiveLock ::DCSIsAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
279bool RecursiveLock ::DCSIsSharedAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
282bool SharedLock ::DCSIsAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
283bool SharedTimedLock ::DCSIsAcquired() const { return Dbg.IsOwnedByCurrentThread(); }
284bool SharedLock ::DCSIsSharedAcquired() const { return Dbg.IsSharedOwnedByAnyThread()
285 || Dbg.IsOwnedByCurrentThread(); }
286bool SharedTimedLock ::DCSIsSharedAcquired() const { return Dbg.IsSharedOwnedByAnyThread()
287 || Dbg.IsOwnedByCurrentThread(); }
288
289#endif
290
291#endif // ALIB_DEBUG
292
293
294// #################################################################################################
295// Globals
296// #################################################################################################
297/// This global mutex is acquired by \alib-types, whenever data is written to either
298/// <c>std::cout</c> or <c>std::cerr</c>.
299/// This is, for example, acquired by type \alib{lang;ReportWriterStdIO} and by loggers of
300/// module \alib_alox that log to the console.
302
303// #################################################################################################
304// DEBUG implementations
305// #################################################################################################
306
307// #################################################################################################
308// Class Lock
309// #################################################################################################
310#if ALIB_DEBUG
311
313{
314 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
315
316 if ( !Dbg.WaitTimeLimit.IsZero() )
317 {
318 Ticks::Duration waitDuration= Dbg.WaitTimeLimit;
319 Ticks overallTimer;
320 Ticks waitTimer;
321 while (!mutex.try_lock_for( (waitDuration - waitTimer.Age()).Export() ) )
322 {
323 if ( waitTimer.Age() < waitDuration )
324 continue; // spurious wakeup
325
326 NString1K msg;
327 msg << "Waiting to acquire a lock since "
328 #if ALIB_CAMP
329 << overallTimer.Age();
330 #else
331 << Dbg.WaitTimeLimit.InAbsoluteMilliseconds() << "ms";
332 #endif
333 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
334
335 waitTimer.Reset();
336 }
337 }
338 else
339 mutex.lock();
340
341 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
343 Dbg.AcqCI= ci;
344}
345
347{
348 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
349
350 if (!mutex.try_lock() )
351 return false;
352
353 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
355 Dbg.AcqCI= ci;
356
357 return true;
358}
359
361{
362 Dbg.AssertOwned ( ALIB_CALLER, ci, "Not acquired" );
363 Dbg.AssertOwning( ALIB_CALLER, ci, "Acquired by a different thread");
364
366 Dbg.RelCI= ci;
367 mutex.unlock();
368}
369
370#endif // ALIB_DEBUG
371
372// #################################################################################################
373// Class TimedLock
374// #################################################################################################
375#if !ALIB_DEBUG
376bool TimedLock::TryAcquireTimed( const Ticks::Duration& waitDuration )
377{
378 Ticks::Duration remainingDuration= waitDuration;
379 Ticks timer;
380 while (!mutex.try_lock_for( remainingDuration.Export() ) )
381 {
382 remainingDuration= waitDuration - timer.Age();
383 if ( remainingDuration.IsPositive() )
384 continue; // spurious wakeup
385 return false;
386 }
387 return true;
388}
389#else
390
392{
393 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
394
395 if ( !Dbg.WaitTimeLimit.IsZero() )
396 {
397 Ticks::Duration waitDuration= Dbg.WaitTimeLimit;
398 Ticks overallTimer;
399 Ticks waitTimer;
400 while (!mutex.try_lock_for( (waitDuration - waitTimer.Age()).Export() ) )
401 {
402 if ( waitTimer.Age() < waitDuration )
403 continue; // spurious wakeup
404
405 NString256 msg;
406 msg << "Waiting to acquire a lock since "
407 #if ALIB_CAMP
408 << overallTimer.Age();
409 #else
410 << Dbg.WaitTimeLimit.InAbsoluteMilliseconds() << "ms";
411 #endif
412 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
413
414 waitTimer.Reset();
415 }
416 }
417 else
418 mutex.lock();
419
420 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
422 Dbg.AcqCI= ci;
423}
424
426{
427 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
428
429 if (!mutex.try_lock() )
430 return false;
431
432 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
433
435 Dbg.AcqCI= ci;
436 return true;
437}
438
439bool TimedLock::TryAcquireTimed( const Ticks::Duration& waitDuration,
440 const CallerInfo& ci )
441{
442 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
443
444 Ticks::Duration remainingDuration= waitDuration;
445 Ticks timer;
446 while (!mutex.try_lock_for( remainingDuration.Export() ) )
447 {
448 remainingDuration= waitDuration - timer.Age();
449 if ( remainingDuration.IsPositive() )
450 continue; // spurious wakeup
451 return false;
452 }
453
454 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
455
457 Dbg.AcqCI= ci;
458 return true;
459}
461{
462 Dbg.AssertOwned ( ALIB_CALLER, ci, "Not acquired" );
463 Dbg.AssertOwning( ALIB_CALLER, ci, "Acquired by a different thread");
464
466 Dbg.RelCI= ci;
467 mutex.unlock();
468}
469
470
471#endif // ALIB_DEBUG
472
473
474// #################################################################################################
475// Class RecursiveLock
476// #################################################################################################
477#if ALIB_DEBUG
479{
480 if ( !Dbg.WaitTimeLimit.IsZero() )
481 {
482 Ticks::Duration waitDuration= Dbg.WaitTimeLimit;
483 Ticks overallTimer;
484 Ticks waitTimer;
485 while (!mutex.try_lock_for( (waitDuration - waitTimer.Age()).Export() ) )
486 {
487 if ( waitTimer.Age() < waitDuration )
488 continue; // spurious wakeup
489
490 NString1K msg;
491 msg << "Waiting to acquire a lock since "
492 #if ALIB_CAMP
493 << overallTimer.Age();
494 #else
495 << Dbg.WaitTimeLimit.InAbsoluteMilliseconds() << "ms";
496 #endif
497 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
498 waitTimer.Reset();
499 }
500 }
501 else
502 mutex.lock();
503
504 Dbg.AssertNotOwnedOrMe( ALIB_CALLER, ci, "Still owned after locking" );
506 Dbg.AcqCI= ci;
507 if( Dbg.RecursionLimit != 0
509 Dbg.DoAssert( 1, ALIB_CALLER, ci,
510 NString256() << Dbg.CntAcquirements << " recursive acquisitions."
511 " Warning limit can be adopted with field DbgRecursionWarningThreshold" );
512}
513
515{
516 if (!mutex.try_lock() )
517 return false;
518
519 Dbg.AssertNotOwnedOrMe( ALIB_CALLER, ci, "Still owned after locking" );
521 Dbg.AcqCI= ci;
522 if( Dbg.RecursionLimit != 0
524 Dbg.DoAssert( 1, ALIB_CALLER, ci,
525 NString256() << Dbg.CntAcquirements << " recursive acquisitions."
526 " Warning limit can be adopted with field DbgRecursionWarningThreshold" );
527 return true;
528}
529
530
532{
533 Dbg.AssertOwned ( ALIB_CALLER, ci, "Not acquired" );
534 Dbg.AssertOwning( ALIB_CALLER, ci, "Not owned");
535
536 Dbg.RelCI = ci;
537 if(--Dbg.CntAcquirements >= 0)
538 mutex.unlock();
539}
540#endif // ALIB_DEBUG
541
542
543// #################################################################################################
544// Class RecursiveTimedLock
545// #################################################################################################
546#if !ALIB_DEBUG
547bool RecursiveTimedLock::TryAcquireTimed( const Ticks::Duration& waitDuration )
548{
549 Ticks::Duration remainingDuration= waitDuration;
550 Ticks timer;
551 while (!mutex.try_lock_for( remainingDuration.Export() ) )
552 {
553 remainingDuration= waitDuration - timer.Age();
554 if ( remainingDuration.IsPositive() )
555 continue; // spurious wakeup
556 return false;
557 }
558 return true;
559}
560#else
562{
563 if ( !Dbg.WaitTimeLimit.IsZero() )
564 {
565 Ticks::Duration waitDuration= Dbg.WaitTimeLimit;
566 Ticks overallTimer;
567 Ticks waitTimer;
568 while (!mutex.try_lock_for( (waitDuration - waitTimer.Age()).Export() ) )
569 {
570 if ( waitTimer.Age() < waitDuration )
571 continue; // spurious wakeup
572
573 NString1K msg;
574 msg << "Waiting to acquire a lock since "
575 #if ALIB_CAMP
576 << overallTimer.Age();
577 #else
578 << Dbg.WaitTimeLimit.InAbsoluteMilliseconds() << "ms";
579 #endif
580 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
581 waitTimer.Reset();
582 }
583 }
584 else
585 mutex.lock();
586
587 Dbg.AssertNotOwnedOrMe( ALIB_CALLER, ci, "Still owned after locking" );
589 Dbg.AcqCI= ci;
590 if( Dbg.RecursionLimit != 0
592 Dbg.DoAssert( 1, ALIB_CALLER, ci,
593 NString256() << Dbg.CntAcquirements << " recursive acquisitions."
594 " Warning limit can be adopted with field DbgRecursionWarningThreshold" );
595}
596
598{
599 if (!mutex.try_lock() )
600 return false;
601
602 Dbg.AssertNotOwnedOrMe( ALIB_CALLER, ci, "Still owned after locking" );
604 Dbg.AcqCI= ci;
605 if( Dbg.RecursionLimit != 0
607 Dbg.DoAssert( 1, ALIB_CALLER, ci,
608 NString256() << Dbg.CntAcquirements << " recursive acquisitions."
609 " Warning limit can be adopted with field DbgRecursionWarningThreshold" );
610 return true;
611}
612
613bool RecursiveTimedLock::TryAcquireTimed( const Ticks::Duration& waitDuration,
614 const CallerInfo& ci )
615{
616 Ticks::Duration remainingDuration= waitDuration;
617 Ticks timer;
618 while (!mutex.try_lock_for( remainingDuration.Export() ) )
619 {
620 remainingDuration= waitDuration - timer.Age();
621 if ( remainingDuration.IsPositive() )
622 continue; // spurious wakeup
623 return false;
624 }
625
626 Dbg.AssertNotOwnedOrMe( ALIB_CALLER, ci, "Still owned after locking" );
628 Dbg.AcqCI= ci;
629 if( Dbg.RecursionLimit != 0
631 Dbg.DoAssert( 1, ALIB_CALLER, ci,
632 NString256() << Dbg.CntAcquirements << " recursive acquisitions."
633 " Warning limit can be adopted with field DbgRecursionWarningThreshold" );
634 return true;
635}
636
638{
639 Dbg.AssertOwned ( ALIB_CALLER, ci, "Not acquired" );
640 Dbg.AssertOwning( ALIB_CALLER, ci, "Not owned");
641
643 Dbg.RelCI= ci;
644 mutex.unlock();
645}
646#endif // ALIB_DEBUG
647
648
649// #################################################################################################
650// Class SharedLock (writer)
651// #################################################################################################
652#if ALIB_DEBUG
654{
655 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
656
657 if ( !Dbg.WaitTimeLimit.IsZero() )
658 {
659 Ticks::Duration waitDuration= Dbg.WaitTimeLimit;
660 Ticks overallTimer;
661 Ticks waitTimer;
662 while (!mutex.try_lock_for( (waitDuration - waitTimer.Age()).Export() ) )
663 {
664 if ( waitTimer.Age() < waitDuration )
665 continue; // spurious wakeup
666
667 NString1K msg;
668 msg << "Waiting to acquire a lock since "
669 #if ALIB_CAMP
670 << overallTimer.Age();
671 #else
672 << Dbg.WaitTimeLimit.InAbsoluteMilliseconds() << "ms";
673 #endif
674 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
675
676 waitTimer.Reset();
677 }
678 }
679 else
680 mutex.lock();
681
682 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
684 Dbg.AcqCI= ci;
685}
686
688{
689 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
690
691 if (!mutex.try_lock() )
692 return false;
693
694 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
696 Dbg.AcqCI= ci;
697 return true;
698}
699
701{
702 Dbg.AssertOwned ( ALIB_CALLER, ci, "Not acquired" );
703 Dbg.AssertOwning( ALIB_CALLER, ci, "Not owned");
704
706 Dbg.RelCI= ci;
707 mutex.unlock();
708}
709
710// #################################################################################################
711// Class SharedLock (reader)
712// #################################################################################################
714{
716 "AcquireShared while already owning. (This is not allowed with std::shared_lock)" );
717
718 if ( !Dbg.WaitTimeLimit.IsZero() )
719 {
720 Ticks::Duration waitDuration= Dbg.WaitTimeLimit;
721 Ticks overallTimer;
722 Ticks waitTimer;
723 while (!mutex.try_lock_shared_for( (waitDuration - waitTimer.Age()).Export() ) )
724 {
725 if ( waitTimer.Age() < waitDuration )
726 continue; // spurious wakeup
727
728 NString1K msg;
729 msg << "Waiting to acquire a lock since "
730 #if ALIB_CAMP
731 << overallTimer.Age();
732 #else
733 << Dbg.WaitTimeLimit.InAbsoluteMilliseconds() << "ms";
734 #endif
735 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
736
737 waitTimer.Reset();
738 }
739 }
740 else
741 mutex.lock_shared();
742
744 Dbg.DoAssert( 1, ALIB_CALLER, ci,
745 "Too many parallel shared acquisitions detected. "
746 "A reason might be that shared acquirers do not call ReleaseShared" );
747
748 Dbg.SAcqCI= ci;
749}
750
752{
754 "AcquireShared while already owning. (This is not allowed with std::shared_lock)" );
755
756 if ( !mutex.try_lock_shared() )
757 return false;
758
759
761 Dbg.DoAssert( 1, ALIB_CALLER, ci,
762 "Too many parallel shared acquisitions detected. "
763 "A reason might be that shared acquirers do not call ReleaseShared" );
764
765 Dbg.SAcqCI= ci;
766 return true;
767}
768
770{
771 auto prevCounter= Dbg.CntSharedAcquirements.fetch_sub(1);
772 if ( prevCounter <= 0 )
773 Dbg.DoAssert( 0, ALIB_CALLER, ci,
774 "Too many invocations of ReleaseShared (from any thread) without prior acquisition" );
775
776 Dbg.SRelCI= ci;
777 mutex.unlock_shared();
778}
779
780#endif // ALIB_DEBUG
781
782
783// #################################################################################################
784// Class SharedTimedLock (writer)
785// #################################################################################################
786#if !ALIB_DEBUG
787bool SharedTimedLock::TryAcquireTimed( const Ticks::Duration& waitDuration )
788{
789 Ticks::Duration remainingDuration= waitDuration;
790 Ticks timer;
791 while (!mutex.try_lock_for( remainingDuration.Export() ) )
792 {
793 remainingDuration= waitDuration - timer.Age();
794 if ( remainingDuration.IsPositive() )
795 continue; // spurious wakeup
796 return false;
797 }
798 return true;
799}
800#else
802{
803 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
804
805 if ( !Dbg.WaitTimeLimit.IsZero() )
806 {
807 Ticks::Duration waitDuration= Dbg.WaitTimeLimit;
808 Ticks overallTimer;
809 Ticks waitTimer;
810 while (!mutex.try_lock_for( (waitDuration - waitTimer.Age()).Export() ) )
811 {
812 if ( waitTimer.Age() < waitDuration )
813 continue; // spurious wakeup
814
815 NString1K msg;
816 msg << "Waiting to acquire a lock since "
817 #if ALIB_CAMP
818 << overallTimer.Age();
819 #else
820 << Dbg.WaitTimeLimit.InAbsoluteMilliseconds() << "ms";
821 #endif
822 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
823
824 waitTimer.Reset();
825 }
826 }
827 else
828 mutex.lock();
829
830 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
832 Dbg.AcqCI= ci;
833}
835{
836 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
837
838 if (!mutex.try_lock() )
839 return false;
840
841 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
843 Dbg.AcqCI= ci;
844 return true;
845}
846
847bool SharedTimedLock::TryAcquireTimed( const Ticks::Duration& waitDuration,
848 const CallerInfo& ci )
849{
850 Dbg.AssertNotOwning( ALIB_CALLER, ci, "Illegal nested acquisition" );
851
852 Ticks::Duration remainingDuration= waitDuration;
853 Ticks timer;
854 while (!mutex.try_lock_for( remainingDuration.Export() ) )
855 {
856 remainingDuration= waitDuration - timer.Age();
857 if ( remainingDuration.IsPositive() )
858 continue; // spurious wakeup
859 return false;
860 }
861
862 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
864 Dbg.AcqCI= ci;
865 return true;
866}
867
869{
870 Dbg.AssertOwned ( ALIB_CALLER, ci, "Not acquired" );
871 Dbg.AssertOwning( ALIB_CALLER, ci, "Not owned");
872
874 Dbg.RelCI= ci;
875 mutex.unlock();
876}
877#endif
878
879// #################################################################################################
880// Class SharedTimedLock (reader)
881// #################################################################################################
882#if !ALIB_DEBUG
883bool SharedTimedLock::TryAcquireSharedTimed( const Ticks::Duration& waitDuration )
884{
885 Ticks::Duration remainingDuration= waitDuration;
886 Ticks timer;
887 while (!mutex.try_lock_shared_for( remainingDuration.Export() ) )
888 {
889 remainingDuration= waitDuration - timer.Age();
890 if ( remainingDuration.IsPositive() )
891 continue; // spurious wakeup
892 return false;
893 }
894 return true;
895}
896
897#else
898
900{
902 "AcquireShared while already owning. (This is not allowed with std::shared_lock)" );
903
904 if ( !Dbg.WaitTimeLimit.IsZero() )
905 {
906 Ticks::Duration waitDuration= Dbg.WaitTimeLimit;
907 Ticks overallTimer;
908 Ticks waitTimer;
909 while (!mutex.try_lock_shared_for( (waitDuration - waitTimer.Age()).Export() ) )
910 {
911 if ( waitTimer.Age() < waitDuration )
912 continue; // spurious wakeup
913
914 NString1K msg;
915 msg << "Waiting to acquire a lock since "
916 #if ALIB_CAMP
917 << overallTimer.Age();
918 #else
919 << Dbg.WaitTimeLimit.InAbsoluteMilliseconds() << "ms";
920 #endif
921 Dbg.DoAssert( 1, ALIB_CALLER, ci, msg);
922
923 waitTimer.Reset();
924 }
925 }
926 else
927 mutex.lock_shared();
928
929 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
930
932 Dbg.DoAssert( 1, ALIB_CALLER, ci,
933 "Too many parallel shared acquisitions detected. "
934 "A reason might be that shared acquirers do not call ReleaseShared" );
935
936 Dbg.SAcqCI= ci;
937}
938
940{
942 "AcquireShared while already owning. (This is not allowed with std::shared_lock)" );
943
944 if ( !mutex.try_lock_shared() )
945 return false;
946
947 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
948
950 Dbg.DoAssert( 1, ALIB_CALLER, ci,
951 "Too many parallel shared acquisitions detected. "
952 "A reason might be that shared acquirers do not call ReleaseShared" );
953
954 Dbg.SAcqCI= ci;
955 return true;
956}
957
958bool SharedTimedLock::TryAcquireSharedTimed( const Ticks::Duration& waitDuration,
959 const CallerInfo& ci )
960{
962 "AcquireShared while already owning. (This is not allowed with std::shared_lock)" );
963
964 Ticks::Duration remainingDuration= waitDuration;
965 Ticks timer;
966 while (!mutex.try_lock_shared_for( remainingDuration.Export() ) )
967 {
968 remainingDuration= waitDuration - timer.Age();
969 if ( remainingDuration.IsPositive() )
970 continue; // spurious wakeup
971 return false;
972 }
973
974 Dbg.AssertNotOwned( ALIB_CALLER, ci, "Still owned after locking" );
975
977 Dbg.DoAssert( 1, ALIB_CALLER, ci,
978 "Too many parallel shared acquisitions detected. "
979 "A reason might be that shared acquirers do not call ReleaseShared" );
980
981 Dbg.SAcqCI= ci;
982 return true;
983}
984
986{
987 auto prevCounter= Dbg.CntSharedAcquirements.fetch_sub(1);
988 if ( prevCounter <= 0 )
989 Dbg.DoAssert( 0, ALIB_CALLER, ci,
990 "Too many invocations of ReleaseShared (from any thread) without prior acquisition" );
991
992 Dbg.SRelCI= ci;
993 mutex.unlock_shared();
994}
995
996#endif // ALIB_DEBUG
997
998}} // namespace [alib::threads]
Formatter & Format(AString &target, TArgs &&... args)
static ALIB_API textlogger::TextLogger * DebugLogger
The debug logger created by AddDebugLogger.
Definition log.inl:43
FormatMultiLine & GetFormatMultiLine()
std::mutex mutex
Definition lock.hpp:71
DbgLockAsserter Dbg
The debug tool instance.
Definition lock.hpp:78
ALIB_API bool TryAcquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:346
ALIB_API void Acquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:312
ALIB_API void Release(ALIB_DBG_TAKE_CI)
Definition locks.cpp:360
DbgLockAsserter Dbg
The debug tool instance.
ALIB_API void AcquireRecursive(ALIB_DBG_TAKE_CI)
Definition locks.cpp:478
std::recursive_mutex mutex
ALIB_API void ReleaseRecursive(ALIB_DBG_TAKE_CI)
Definition locks.cpp:531
ALIB_API bool TryAcquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:514
virtual ALIB_API bool DCSIsAcquired() const override
Definition locks.cpp:280
ALIB_API bool TryAcquireTimed(const Ticks::Duration &waitDuration, const CallerInfo &ci)
Definition locks.cpp:613
DbgLockAsserter Dbg
The debug tool instance.
virtual ALIB_API bool DCSIsSharedAcquired() const override
Definition locks.cpp:281
ALIB_API void AcquireRecursive(ALIB_DBG_TAKE_CI)
Definition locks.cpp:561
ALIB_API void ReleaseRecursive(ALIB_DBG_TAKE_CI)
Definition locks.cpp:637
ALIB_API bool TryAcquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:597
std::recursive_timed_mutex mutex
The internal object to lock on.
ALIB_API bool TryAcquireShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:751
ALIB_API void AcquireShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:713
DbgSharedLockAsserter Dbg
The debug tool instance.
std::shared_mutex mutex
ALIB_API void ReleaseShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:769
ALIB_API bool TryAcquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:687
ALIB_API void Acquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:653
ALIB_API void Release(ALIB_DBG_TAKE_CI)
Definition locks.cpp:700
std::atomic< int > DbgWarningMaximumShared
ALIB_API bool TryAcquireShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:939
ALIB_API bool TryAcquireTimed(const Ticks::Duration &waitDuration, const CallerInfo &ci)
Definition locks.cpp:847
ALIB_API void AcquireShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:899
DbgSharedLockAsserter Dbg
The debug tool instance.
ALIB_API bool TryAcquireSharedTimed(const Ticks::Duration &waitDuration, const CallerInfo &ci)
Definition locks.cpp:958
std::shared_timed_mutex mutex
The internal object to lock on.
ALIB_API void ReleaseShared(ALIB_DBG_TAKE_CI)
Definition locks.cpp:985
ALIB_API bool TryAcquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:834
ALIB_API void Acquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:801
ALIB_API void Release(ALIB_DBG_TAKE_CI)
Definition locks.cpp:868
std::atomic< int > DbgWarningMaximumShared
static ALIB_API Thread * Get(std::thread::id nativeID)
Definition thread.cpp:321
ALIB_API bool TryAcquireTimed(const Ticks::Duration &waitDuration, const CallerInfo &ci)
Definition locks.cpp:439
std::timed_mutex mutex
The internal object to lock on.
Definition timedlock.hpp:62
DbgLockAsserter Dbg
The debug tool instance.
Definition timedlock.hpp:67
ALIB_API bool TryAcquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:425
ALIB_API void Acquire(ALIB_DBG_TAKE_CI)
Definition locks.cpp:391
ALIB_API void Release(ALIB_DBG_TAKE_CI)
Definition locks.cpp:460
#define ALIB_DBG_TAKE_CI
Definition alib.hpp:1176
#define ALIB_CALLER
Definition alib.hpp:1164
#define ALIB_STRINGS_TO_NARROW( src, dest, bufSize)
ALIB_API Lock STD_IOSTREAMS_LOCK
Definition locks.cpp:301
Definition alib.cpp:69
NLocalString< 256 > NString256
Type alias name for TLocalString<nchar,256>.
lang::integer integer
Type alias in namespace alib.
Definition integers.hpp:273
std::thread::id ThreadID
The ID of the calling thread.
Definition alib.hpp:1136
const char * Func
Definition alib.hpp:1132
CallerInfo WaitCI
The most recent call to WaitForNotification.
Definition condition.hpp:42
CallerInfo AcqCI
Source location of the most recent acquirement.
Definition condition.hpp:40
CallerInfo RelCI
Source location of the most recent release.
Definition condition.hpp:41
CallerInfo NotifyCI
The most recent call to ReleaseAndNotify or.
Definition condition.hpp:43
ALIB_API void Assert(bool cond, const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline)
Definition locks.cpp:223
String Name
The name of this instance.
Definition condition.hpp:38
static ALIB_API NString ASSERTION_FORMAT
std::atomic< int > CntWaiters
The number of currently waiting threads.
Definition condition.hpp:44
Thread * Owner
Tracks the current owner.
Definition condition.hpp:39
ALIB_API Thread * GetOwner() const
Definition locks.cpp:43
int16_t CntAcquirements
The number of nested acquirements.
void AssertNotOwned(const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline)
void AssertNotOwning(const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline)
CallerInfo AcqCI
Source location of the most recent acquirement.
void AssertNotOwnedOrMe(const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline)
CallerInfo RelCI
Source location of the most recent release.
void AssertOwning(const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline)
virtual ALIB_API void DoAssert(int type, const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline)
Definition locks.cpp:97
static ALIB_API NString ASSERTION_FORMAT
void AssertOwned(const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline)
void AssertNotOwned(const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline)
std::atomic< int > CntSharedAcquirements
The number of shared acquirements.
CallerInfo SAcqCI
Source location of the most recent shared acquirement.
ALIB_API void DoAssert(int type, const CallerInfo &assertCI, const CallerInfo &ci, const NString &headline) override
Definition locks.cpp:142
CallerInfo SRelCI
Source location of the most recent shared release.
static ALIB_API NString ASSERTION_FORMAT_SHARED