// ############################################################################################# // Interface // ############################################################################################# /** **************************************************************************************** * Adds an acquirer. * @param newAcquirer The acquirer to add. * @return The new number of \e acquirers set. ******************************************************************************************/ public virtual int AddAcquirer(ThreadLock newAcquirer) { int count = -1; #if DEBUG bool errAllreadyAdded = true; bool errHasToBeRecursive = false; int errWasAcquired = 0; #endif try { ALIB.Lock.Acquire(); count = acquirers.Count; // check doubly added if (newAcquirer == null || acquirers.IndexOf(newAcquirer) < 0) { #if DEBUG errAllreadyAdded = false; errWasAcquired = DbgCountAcquirements() == 0 ? 0 : 1; #endif // switch on? if (acquirers.Count == 1) { #if DEBUG errAllreadyAdded = false; #endif ThreadLock firstAcquirer = acquirers[0]; // non-anonymous acquirer? if (firstAcquirer != null) { if (firstAcquirer.GetMode() == LockMode.Recursive) { firstAcquirer.Acquire(); SetSafeness(Safeness.Safe); acquirers.Add(newAcquirer); count++; firstAcquirer.Release(); } #if DEBUG else { errHasToBeRecursive = false; } #endif } // critical section: our first acquirer is anonymous. As documented in class, // this must happen only in situations, when we are sure, that we are safe, e.g. still // single threaded execution of process bootstrap. else { // If this assert happens, its only good luck: we detected a misuse. But it should // be very seldom to be detected this way :-/ #if DEBUG if (errWasAcquired == 1) { errWasAcquired = 2; } #endif SetSafeness(Safeness.Safe); acquirers.Add(newAcquirer); count++; } } else { acquirers.Add(newAcquirer); } } } finally { ALIB.Lock.Release(); } #if DEBUG ALIB.ASSERT_ERROR(!errAllreadyAdded, "Acquirer already registered."); ALIB.ASSERT_ERROR(!errHasToBeRecursive, "Acquireres need to be in recursive mode "); ALIB.ASSERT_ERROR(errWasAcquired != 1, "Already aquired. Hint: Acquirer[0] must not acquire this before adding itself!"); ALIB.ASSERT_ERROR(errWasAcquired != 2, "Aquired and acquirer[0] anonymous. Misuse of SmartLock!"); #endif return(count); }
/** **************************************************************************************** * Removes an acquirer. * @param acquirerToRemove The acquirer to remove. * @return The new number of \e acquirers set. ******************************************************************************************/ public virtual int RemoveAcquirer(ThreadLock acquirerToRemove) { int count = 0; bool errNotFound = true; bool errWasAcquired = false; try { ALIB.Lock.Acquire(); #if DEBUG errWasAcquired = DbgCountAcquirements() != 0; #endif // search acquirer if (acquirers.IndexOf(acquirerToRemove) >= 0) { errNotFound = false; // switch off? if (acquirers.Count == 2) { ThreadLock acquirer1 = acquirers[0]; ThreadLock acquirer2 = acquirers[1]; if (acquirer1 == acquirerToRemove) { acquirer1 = null; } if (acquirer2 == acquirerToRemove) { acquirer2 = null; } // Aquire acquirers in their order of appearance if (acquirer1 != null) { acquirer1.Acquire(); } if (acquirer2 != null) { acquirer2.Acquire(); } SetSafeness(Safeness.Unsafe); acquirers.Remove(acquirerToRemove); if (acquirer2 != null) { acquirer2.Release(); } if (acquirer1 != null) { acquirer1.Release(); } } // just remove acquirer, keep mode else { acquirers.Remove(acquirerToRemove); } } count = acquirers.Count; } finally { ALIB.Lock.Release(); } ALIB.ASSERT_ERROR(!errNotFound, "Acquirer not found."); ALIB.ASSERT_ERROR(!errWasAcquired, "Aquired on release. Hint: Acquirers must acquire only when acquired themselves!"); return(count); }
public void ThreadLock_SpeedTest() { UT_INIT(); Log.SetVerbosity( new ConsoleLogger(), Verbosity.Verbose, "/" ); Log.MapThreadName( "UnitTest" ); Log.SetDomain( "TestTLock", Scope.Method ); ThreadLock aLock= new ThreadLock(); int repeats= 100000; int rrepeats= 5; Ticks stopwatch= new Ticks(); for ( int r= 0; r < rrepeats; r ++) { Log.Info("Run " + rrepeats ); aLock.SetSafeness( Safeness.Unsafe ); stopwatch.Set(); for ( int i= 0; i < repeats; i++ ) { aLock.Acquire(); aLock.Release(); } long time= stopwatch.Age().InMillis(); Log.Info("Safe mode, " + repeats + " lock/unlock ops: " + time + " ms" ); aLock.SetSafeness( Safeness.Safe ); stopwatch.Set(); for ( int i= 0; i < repeats; i++ ) { //aLock.acquire(); //aLock.release(); // in java, adding the following two loops, results in similar execution speed for ( int tt= 0; tt < 70; tt++ ) i+= tt; for ( int tt= 0; tt < 70; tt++ ) i-= tt; } time= stopwatch.Age().InMillis(); Log.Info("Unsafe mode, " + repeats + " lock/unlock ops: " + time + " ms" ); } }
public void ThreadLock_Simple() { UT_INIT(); Report.GetDefault().PushHaltFlags( false, false ); Log.AddDebugLogger(); Log.MapThreadName( "UnitTest" ); Log.SetDomain( "TestTLock", Scope.Method ); Log.SetVerbosity( Log.DebugLogger, Verbosity.Verbose, "ALIB" ); // lock a recursive lock ThreadLock aLock= new ThreadLock(); aLock.Acquire(); aLock.Release(); aLock.Acquire(); UT_TRUE ( aLock.ToString().StartsWith("Locked") ); aLock.Acquire(); UT_TRUE ( aLock.ToString().StartsWith("Locked") ); aLock.Release(); UT_TRUE ( aLock.ToString().StartsWith("Locked") ); aLock.Acquire(); UT_TRUE ( aLock.ToString().StartsWith("Locked") ); aLock.Release(); UT_TRUE ( aLock.ToString().StartsWith("Locked") ); aLock.Release(); UT_TRUE ( aLock.ToString().StartsWith("Unlocked") ); // set unsafe aLock.SetSafeness( Safeness.Unsafe ); UT_TRUE ( aLock.ToString().StartsWith("Unlocked") ); UT_TRUE ( aLock.ToString().Contains ("Unsafe") ); aLock.SetSafeness( Safeness.Safe ); UT_TRUE ( !aLock.ToString().Contains ("Unsafe") ); aLock.SetSafeness( Safeness.Unsafe ); UT_TRUE ( aLock.ToString().StartsWith("Unlocked") ); UT_TRUE ( aLock.ToString().Contains ("Unsafe") ); aLock.Acquire(); UT_TRUE ( aLock.ToString().StartsWith("Locked") ); aLock.Release(); UT_TRUE ( aLock.ToString().StartsWith("Unlocked") ); UT_TRUE ( aLock.ToString().Contains ("Unsafe") ); // unsafe aLock.Acquire(); UT_TRUE ( aLock.ToString().StartsWith("Locked") ); Log.Info("One warning should come now: "); aLock.SetSafeness( Safeness.Safe ); UT_TRUE ( aLock.ToString().StartsWith("Locked") ); UT_TRUE ( aLock.ToString().Contains ("Unsafe") ); // safe (new lock) aLock= new ThreadLock(); aLock.Acquire(); UT_TRUE ( aLock.ToString().StartsWith("Locked") ); UT_TRUE ( !aLock.ToString().Contains ("Unsafe") ); Log.Info("One warning should come now: "); aLock.SetSafeness( Safeness.Unsafe ); UT_TRUE ( !aLock.ToString().StartsWith("null") ); UT_TRUE ( !aLock.ToString().Contains ("Unsafe") ); // test warnings (10) locks: aLock= new ThreadLock(); Log.Info("Two warnings should come now: "); for (int i= 0; i<20; i++) aLock.Acquire(); UT_TRUE ( aLock.ToString().StartsWith("Locked") ); for (int i= 0; i<20; i++) aLock.Release(); UT_TRUE ( aLock.ToString().StartsWith("Unlocked") ); // test a non-recursive lock aLock= new ThreadLock( LockMode.SingleLocks ); aLock.Acquire(); UT_TRUE ( aLock.ToString().StartsWith("Locked") ); aLock.Acquire(); UT_TRUE ( aLock.ToString().StartsWith("Locked") ); aLock.Release(); UT_TRUE ( aLock.ToString().StartsWith("Unlocked") ); Log.Info("One warning should come now: "); aLock.Release(); UT_TRUE ( aLock.ToString().StartsWith("Unlocked") ); Report.GetDefault().PopHaltFlags(); }
public void ThreadLock_Threaded() { UT_INIT(); Log.SetVerbosity( new ConsoleLogger(),Verbosity.Verbose, "/" ); Log.MapThreadName( "UnitTest" ); Log.SetDomain( "TestTLock", Scope.Filename ); Log.SetVerbosity( "CONSOLE", Verbosity.Verbose, "ALIB" ); ThreadLock aLock= new ThreadLock(); Test_ThreadLock_SharedInt shared= new Test_ThreadLock_SharedInt(); Log.Info("starting thread locked"); aLock.Acquire(); Test_ThreadLock_TestThreadParams tParam= new Test_ThreadLock_TestThreadParams( aLock, 10, 1, true, shared ); Thread thread = new Thread( new ParameterizedThreadStart( Test_ThreadLock_Test_run ) ); thread.Name= "A Thread"; thread.Start( tParam ); Log.Info("We wait 1100 ms. This should give a warning! "); ALIB.SleepMillis( 1100 ); aLock.Release(); // wait until t ended while (thread.IsAlive) ALIB.SleepMillis( 1 ); // now we do the same with a higher wait limit, no erro should come aLock.waitWarningTimeLimitInMillis= 5; aLock.Acquire(); tParam= new Test_ThreadLock_TestThreadParams( aLock, 10, 1, true, shared ); thread = new Thread( new ParameterizedThreadStart( Test_ThreadLock_Test_run ) ); thread.Start( tParam ); Log.Info("We wait 1 ms. This should NOT give a warning! "); ALIB.SleepMillis( 1 ); aLock.Release(); // wait until t ended while (thread.IsAlive) ALIB.SleepMillis( 1 ); }