private static void Main(string[] args) { SpinLock slock = new SpinLock(false); long sum1 = 0; long sum2 = 0; Parallel.For(0, 10000, i => { sum1 += i; }); Parallel.For(0, 10000, i => { bool lockTaken = false; try { slock.Enter(ref lockTaken); sum2 += i; } finally { if (lockTaken) slock.Exit(false); } }); Console.WriteLine("Num1的值为:{0}", sum1); Console.WriteLine("Num2的值为:{0}", sum2); }
// SpinLock работает на interlocked-конструкции // соответственно, применять можно, когда // время нахождения в критической секции минимально // и/или необходимо много блокировок public static void SpinLockUsage() { SpinLock spinLock = new SpinLock(); bool lockTaken = false; spinLock.Enter(ref lockTaken); // код критической секции spinLock.Exit(); }
static void Main(string[] args) { var slock = new SpinLock(); bool taken = false; try { slock.Enter(ref taken); DoSomething(); } finally { if (taken) slock.Exit(); } }
public void RecursionExceptionTest () { sl = new SpinLock (true); bool taken = false, taken2 = false; sl.Enter (ref taken); Assert.IsTrue (taken, "#1"); sl.Enter (ref taken2); }
/// <summary>Takes an array from the bucket. If the bucket is empty, returns null.</summary> internal T[] Rent() { T[][] buffers = _buffers; T[] buffer = null; // While holding the lock, grab whatever is at the next available index and // update the index. We do as little work as possible while holding the spin // lock to minimize contention with other threads. The try/finally is // necessary to properly handle thread aborts on platforms which have them. bool lockTaken = false, allocateBuffer = false; try { #if SERVERSIDE _lock.Enter(ref lockTaken); #endif if (_index < buffers.Length) { buffer = buffers[_index]; buffers[_index++] = null; allocateBuffer = buffer == null; } } finally { #if SERVERSIDE if (lockTaken) { _lock.Exit(false); } #endif } // While we were holding the lock, we grabbed whatever was at the next available index, if // there was one. If we tried and if we got back null, that means we hadn't yet allocated // for that slot, in which case we should do so now. if (allocateBuffer) { buffer = new T[_bufferLength]; #if SERVERSIDE var log = ArrayPoolEventSource.Log; if (log.IsEnabled()) { log.BufferAllocated(buffer.GetHashCode(), _bufferLength, _poolId, Id, ArrayPoolEventSource.BufferAllocatedReason.Pooled); } #endif } return(buffer); }
private static int CreateTypeIndexThreadSafe(Type type) { int num2; bool lockTaken = false; try { s_CreateTypeLock.Enter(ref lockTaken); int index = FindTypeIndex(type, s_Count); if (index != -1) { num2 = index; } else { s_Count++; index = s_Count; s_Types[index] = BuildComponentType(type); num2 = index; } } finally { if (lockTaken) { s_CreateTypeLock.Exit(true); } } return(num2); }
private void WriteToFile() { bool isLockTaken = false; spin.Enter(ref isLockTaken); File.AppendAllText(_fileName, $"{nameof(SpinLock)}: {DateTime.Now:hh:mm:ss:ffff} {Environment.NewLine}"); spin.Exit(false); }
public static T Exchange <T>(ref T target, T newValue) { bool lockTaken = false; try { spinLock.Enter(ref lockTaken); T originalValue = target; target = newValue; return(originalValue); } finally { if (lockTaken) { spinLock.Exit(false); } } }
public void IsHeldByCurrentThreadTest() { bool lockTaken = false; sl.Enter(ref lockTaken); Assert.IsTrue(lockTaken, "#1"); Assert.IsTrue(sl.IsHeldByCurrentThread, "#2"); lockTaken = false; sl = new SpinLock(true); sl.Enter(ref lockTaken); Assert.IsTrue(lockTaken, "#3"); Assert.IsTrue(sl.IsHeldByCurrentThread, "#4"); }
public void SemanticCorrectnessTest () { sl = new SpinLock (false); bool taken = false; bool taken2 = false; sl.Enter (ref taken); Assert.IsTrue (taken, "#1"); sl.TryEnter (ref taken2); Assert.IsFalse (taken2, "#2"); sl.Exit (); sl.TryEnter (ref taken2); Assert.IsTrue (taken2, "#3"); }
public void WithLock(Action action) { bool lockAcquired = false; try { _lock.Enter(ref lockAcquired); action(); } finally { if (lockAcquired) { _lock.Exit(true); } } }
static void Main(string[] args) { // create the bank account instance BankAccount account = new BankAccount(); // create the spinlock SpinLock spinlock = new SpinLock(); // create an array of tasks Task[] tasks = new Task[10]; for (int i = 0; i < 10; i++) { // create a new task tasks[i] = new Task(() => { // enter a loop for 1000 balance updates for (int j = 0; j < 1000; j++) { bool lockAcquired = false; try { spinlock.Enter(ref lockAcquired); // update the balance account.Balance = account.Balance + 1; } finally { if (lockAcquired) spinlock.Exit(); } } }); // start the new task tasks[i].Start(); } // wait for all of the tasks to complete Task.WaitAll(tasks); // write out the counter value Console.WriteLine("Expected value {0}, Balance: {1}", 10000, account.Balance); // wait for input before exiting Console.WriteLine("Press enter to finish"); Console.ReadLine(); }
public void LocalPush(IThreadPoolWorkItem obj) { int tail = m_tailIndex; // We're going to increment the tail; if we'll overflow, then we need to reset our counts if (tail == int.MaxValue) { bool lockTaken = false; try { m_foreignLock.Enter(ref lockTaken); if (m_tailIndex == int.MaxValue) { // // Rather than resetting to zero, we'll just mask off the bits we don't care about. // This way we don't need to rearrange the items already in the queue; they'll be found // correctly exactly where they are. One subtlety here is that we need to make sure that // if head is currently < tail, it remains that way. This happens to just fall out from // the bit-masking, because we only do this if tail == int.MaxValue, meaning that all // bits are set, so all of the bits we're keeping will also be set. Thus it's impossible // for the head to end up > than the tail, since you can't set any more bits than all of // them. // m_headIndex = m_headIndex & m_mask; m_tailIndex = tail = m_tailIndex & m_mask; Debug.Assert(m_headIndex <= m_tailIndex); } } finally { if (lockTaken) { m_foreignLock.Exit(useMemoryBarrier: true); } } } // When there are at least 2 elements' worth of space, we can take the fast path. if (tail < m_headIndex + m_mask) { Volatile.Write(ref m_array[tail & m_mask], obj); m_tailIndex = tail + 1; } else { // We need to contend with foreign pops, so we lock. bool lockTaken = false; try { m_foreignLock.Enter(ref lockTaken); int head = m_headIndex; int count = m_tailIndex - m_headIndex; // If there is still space (one left), just add the element. if (count >= m_mask) { // We're full; expand the queue by doubling its size. var newArray = new IThreadPoolWorkItem[m_array.Length << 1]; for (int i = 0; i < m_array.Length; i++) { newArray[i] = m_array[(i + head) & m_mask]; } // Reset the field values, incl. the mask. m_array = newArray; m_headIndex = 0; m_tailIndex = tail = count; m_mask = (m_mask << 1) | 1; } Volatile.Write(ref m_array[tail & m_mask], obj); m_tailIndex = tail + 1; } finally { if (lockTaken) { m_foreignLock.Exit(useMemoryBarrier: false); } } } }
string getFileName() { // Find name of database file try { //string databaseFilePath = (string)ConfigurationManager.AppSettings["databaseFile"]; string databaseFilePath = Properties.Settings.Default.databaseFile; if (databaseFilePath == null || databaseFilePath.Length == 0) { throw new Exception("No database file path exists in user settings"); } bool done = false; string messageToDisplay = "An Acry database has been used on this user's profile before. The database was:\n\n" + databaseFilePath + "\n\nWould you like to continue to use that data file?"; // We need to ask the user a yes/no question, but we are running on the background worker thread. // Init the Messagebox with a value that a yes/no could never give MessageBoxResult usrRslt = MessageBoxResult.None; // Outermost loop that forces the worker to raise a single request to the UI thread and then wait in a loop do { bool slaveHasLock = false; // Tell the program dispatcher to get the main thread to handle the UI dialog this.Dispatcher.BeginInvoke((Action)(() => { bool lockAcq = false; // Grab the spinlock usrLock.Enter(ref lockAcq); // If we have the spinlock, update the value of usrRslt with the response if (lockAcq) { usrRslt = System.Windows.MessageBox.Show(messageToDisplay, "Acry Database file found", System.Windows.MessageBoxButton.YesNo, System.Windows.MessageBoxImage.Question); } usrLock.Exit(); } )); do { // After queueing the work for the main thread the worker thread enters here and tries to grab the spinlock usrLock.Enter(ref slaveHasLock); // If we have the lock (must be checked first before checking value of usrRslt to ensure sync with main thread) then proceed with our logic if (slaveHasLock && usrRslt != MessageBoxResult.None) { switch (usrRslt) { case System.Windows.MessageBoxResult.Yes: // Make sure we release the lock before we return usrLock.Exit(); return(databaseFilePath); case System.Windows.MessageBoxResult.No: done = true; break; default: acryWrite("Invalid response."); done = true; break; } } // Release the lock usrLock.Exit(); slaveHasLock = false; } while (!done); } while (!done); throw new Exception("A new database file must be selected!"); } catch (Exception ex) { // For one reason or another we cannot find the database file. Select a new one. acryWrite(ex.Message, true); acryWrite("Please select database file"); // Set the file name to something impossible string toBeOutput = "merp"; // Ask the dispatcher to send the main thread to go get the file name this.Dispatcher.BeginInvoke((Action)(() => { bool haveLock = false; usrLock.Enter(ref haveLock); if (haveLock) { toBeOutput = getNewFilePath(); } usrLock.Exit(); } )); bool done = false; // Send the worker thread into a look of acquiring the lock and checking the output do { bool haveLock = false; usrLock.Enter(ref haveLock); if (haveLock && !toBeOutput.Equals("merp")) { usrLock.Exit(); done = true; } else { usrLock.Exit(); System.Threading.Thread.Sleep(100); } } while (!done); return(toBeOutput); } }
private static void RemoveNoise(NeuralComputation computation, string path, double noiseLevel) { var comps = Enumerable.Range(0, 15).Select(idx => new NoiseRemovalComputation(computation.Clone())).ToList(); comps.Add(new NoiseRemovalComputation(computation)); int compIdx = 0; ImageBuffer source, dest; using (var sourceBmp = new Bitmap(path)) { source = new ImageBuffer(sourceBmp); AddNoise(source, noiseLevel); dest = new ImageBuffer(source.Width, source.Height); } int size = 7, blockSize = 16; int w = source.Width, h = source.Height, soFar = 0, msTime = 0; SpinLock infoLock = new SpinLock(), compLock = new SpinLock(); Parallel.For(0, h / blockSize + 1, (idx, state) => { NoiseRemovalComputation comp; bool compTaken = false; try { compLock.Enter(ref compTaken); comp = comps[compIdx++ % comps.Count]; } finally { if (compTaken) compLock.Exit(); } //Console.WriteLine(compIdx); int pos = idx * blockSize; var rBytes = new byte[size * size]; var bBytes = new byte[size * size]; var gBytes = new byte[size * size]; Color[] sourceColors = new Color[size * size]; for (int y = pos; y < pos + blockSize && y < h; y++) { var sw = new Stopwatch(); for (int x = 0; x < w; x++) { ReadBytes(source, rBytes, gBytes, bBytes, size, x, y); sw.Start(); byte destByteR = comp.Compute(rBytes, noiseLevel); byte destByteG = comp.Compute(gBytes, noiseLevel); byte destByteB = comp.Compute(bBytes, noiseLevel); sw.Stop(); WriteByte(dest, x, y, destByteR, destByteG, destByteB); } bool infoTaken = false; try { infoLock.Enter(ref infoTaken); msTime += (int)sw.ElapsedMilliseconds; Console.WriteLine("Processing line: {0} / {1}", ++soFar, h); } finally { if (infoTaken) infoLock.Exit(); } } }); Console.WriteLine("Comp: {0}ms", msTime); dest.Save("result.png", ImageFormat.Png); }
/// <summary> /// Test SpinLock.Enter by launching n threads that increment a variable inside a critical section /// the final count variable must be equal to n /// </summary> /// <param name="threadsCount">Number of threads that call enter/exit</param> /// <returns>True if succeeded, false otherwise</returns> private static bool RunSpinLockTest0_Enter(int threadsCount, bool enableThreadIDs) { TestHarness.TestLog("SpinLock.Enter(" + threadsCount + " threads)"); // threads array Thread[] threads = new Thread[threadsCount]; //spinlock object SpinLock slock = new SpinLock(enableThreadIDs); // scceeded threads counter int succeeded = 0; // Semaphore used to make sure that there is no other threads in the critical section Semaphore semaphore = new Semaphore(1, 1); for (int i = 0; i < threadsCount; i++) { threads[i] = new Thread(delegate() { bool lockTaken = false; try { slock.Enter(ref lockTaken); //use semaphore to make sure that no other thread inside the critical section if (!semaphore.WaitOne(0, false)) { // This mean that there is another thread in the critical section return; } succeeded++; if (slock.IsThreadOwnerTrackingEnabled && !slock.IsHeldByCurrentThread) { // lock is obtained successfully succeeded--; } } catch { // decrement the count in case of exception succeeded--; } finally { semaphore.Release(); if (lockTaken) { slock.Exit(); } } }); threads[i].Start(); } // wait all threads for (int i = 0; i < threadsCount; i++) { threads[i].Join(); } // count must be equal to the threads count if (succeeded != threadsCount) { TestHarness.TestLog("SpinLock.Enter() failed, actual count: " + succeeded + " expected: " + threadsCount); return false; } TestHarness.TestLog("SpinLock.Enter() passed."); return true; }
/// <summary> /// Test Exit /// </summary> /// <returns>True if succeeded, false otherwise</returns> private static bool RunSpinLockTest4_Exit(bool enableThreadIDs) { TestHarness.TestLog("SpinLock.Exit()"); Exception exception = null; SpinLock slock = new SpinLock(enableThreadIDs); bool lockTaken = false; slock.Enter(ref lockTaken); slock.Exit(); if (enableThreadIDs && slock.IsHeldByCurrentThread) { TestHarness.TestLog("SpinLock.Exit() failed, IsHeld is true after calling Exit"); return false; } // Calling Exit without owning the lock try { slock.Exit(); } catch (Exception ex) { // SynchronizationLockException must be thrown exception = ex; } if (enableThreadIDs) { if (exception == null || exception.GetType() != typeof(SynchronizationLockException)) { TestHarness.TestLog(@"SpinLock.Exit() failed, calling Exit without owning the lock"); return false; } } TestHarness.TestLog("SpinLock.Exit() passed."); return true; }
public TurnInfo NextControl(GameModel gm, out int cx, out int cr) { long callCount = 0, boaderScore = 0; int nowLevel = 0, ci = 0; TurnInfo turnInfo = new TurnInfo(); try { while (!MaxToControl(out ci, boaderScore) && nowLevel++ < maxLevel) { if (!parallel) { SearchStorage ss = CreateLocalStorage(gm, nowLevel, boaderScore); turnInfo = SearchNode(rootNode, 0, ss); boaderScore = ss.MinimaxScore; callCount = ss.CallCount; } else { long minScore = long.MaxValue; long minimaxScore = 0; SpinLock sl = new SpinLock(); if (!rootNode.IsExistChild()) { rootNode.GenerateChild(W, T); } ParallelLoopResult plr = Parallel.For<SearchStorage>(0, rootNode.Length, () => CreateLocalStorage(gm, nowLevel, boaderScore), (index, state, local) => { local.MinimaxScore = long.MinValue; local.CallCount = 0; Debug.Assert(local.GMC.Level == 1); local.resultInfo = AppraiseNode(rootNode[index], 1, 0, local); return local; }, (local) => { bool lockTaken = false; while (!lockTaken) sl.Enter(ref lockTaken); if (turnInfo.AppraisalScore < local.resultInfo.AppraisalScore) { turnInfo = local.resultInfo; } if (local.resultInfo.AppraisalScore >= local.BoaderScore) { minScore = Math.Min(minScore, local.resultInfo.AppraisalScore); } minimaxScore = Math.Max(minimaxScore, local.MinimaxScore); callCount += local.CallCount; sl.Exit(); } ); Debug.Assert(plr.IsCompleted); if (minScore < long.MaxValue) { boaderScore = Math.Max(minimaxScore, minScore); } else { boaderScore = minimaxScore; } } Trace.TraceInformation("Turn {0}, Level {1}, CallCount {2}, BoaderScore {3}, {4}, {5}", gm.Turn + 1, nowLevel, callCount, boaderScore, turnInfo.ToString(), rootNode.ToString()); } } catch (OutOfMemoryException e) { Trace.TraceWarning("{0}", e.ToString()); } if (ci != -1) { rootNode = rootNode[ci]; cx = rootNode.CX; cr = rootNode.CR; } else { rootNode = new AppraisalTree(); cx = 0; cr = 0; } return turnInfo; }
/// <summary> /// Test SpinLock.Enter by launching n threads that increment a variable inside a critical section /// the final count variable must be equal to n /// </summary> /// <param name="threadsCount">Number of threads that call enter/exit</param> /// <returns>True if succeeded, false otherwise</returns> private static void RunSpinLockTest0_Enter(int threadsCount, bool enableThreadIDs) { // threads array Task[] threads = new Task[threadsCount]; //spinlock object SpinLock slock = new SpinLock(enableThreadIDs); // succeeded threads counter int succeeded = 0; // Semaphore used to make sure that there is no other threads in the critical section SemaphoreSlim semaphore = new SemaphoreSlim(1, 1); for (int i = 0; i < threadsCount; i++) { threads[i] = Task.Run(delegate () { bool lockTaken = false; try { slock.Enter(ref lockTaken); //use semaphore to make sure that no other thread inside the critical section if (!semaphore.Wait(0)) { // This mean that there is another thread in the critical section return; } succeeded++; if (slock.IsThreadOwnerTrackingEnabled && !slock.IsHeldByCurrentThread) { // lock is obtained successfully succeeded--; } } catch { // decrement the count in case of exception succeeded--; } finally { semaphore.Release(); if (lockTaken) { slock.Exit(); } } }); } // wait all threads for (int i = 0; i < threadsCount; i++) { threads[i].Wait(); } // count must be equal to the threads count if (succeeded != threadsCount) { Assert.True(false, string.Format("SpinLock.Enter() failed, actual count: " + succeeded + " expected: " + threadsCount)); } }
public static void Go() { Int32 x = 0; const Int32 iterations = 10000000; // 10 million // How long does it take to increment x 10 million times? Stopwatch sw = Stopwatch.StartNew(); for (Int32 i = 0; i < iterations; i++) { x++; } Console.WriteLine("Incrementing x: {0:N0}", sw.ElapsedMilliseconds); // How long does it take to increment x 10 million times // adding the overhead of calling a method that does nothing? sw.Restart(); for (Int32 i = 0; i < iterations; i++) { M(); x++; M(); } Console.WriteLine("Incrementing x in M: {0:N0}", sw.ElapsedMilliseconds); // How long does it take to increment x 10 million times // adding the overhead of calling an uncontended SimpleSpinLock? SimpleSpinLock ssl = new SimpleSpinLock(); sw.Restart(); for (Int32 i = 0; i < iterations; i++) { ssl.Enter(); x++; ssl.Leave(); } Console.WriteLine("Incrementing x in SimpleSpinLock: {0:N0}", sw.ElapsedMilliseconds); // How long does it take to increment x 10 million times // adding the overhead of calling an uncontended SpinLock? SpinLock sl = new SpinLock(false); sw.Restart(); for (Int32 i = 0; i < iterations; i++) { Boolean taken = false; sl.Enter(ref taken); x++; sl.Exit(false); } Console.WriteLine("Incrementing x in SpinLock: {0:N0}", sw.ElapsedMilliseconds); // How long does it take to increment x 10 million times // adding the overhead of calling an uncontended SimpleWaitLock? using (SimpleWaitLock swl = new SimpleWaitLock()) { sw.Restart(); for (Int32 i = 0; i < iterations; i++) { swl.Enter(); x++; swl.Leave(); } Console.WriteLine("Incrementing x in SimpleWaitLock: {0:N0}", sw.ElapsedMilliseconds); } Console.ReadLine(); }
public static void Do(int workItemsCount, bool parallelize, Action<DataParallelContext> workItemRangeProcessor) { if (workItemsCount <= 0 || workItemRangeProcessor == null) return; if (!parallelize) { workItemRangeProcessor(new DataParallelContext(IntRange.CreateExclusive(0, workItemsCount), workItemsCount)); return; } if (workItemsCount == 1) { workItemRangeProcessor(new DataParallelContext(IntRange.CreateFixed(0), workItemsCount)); } else if (workItemsCount < procCount) { Parallel.For(0, workItemsCount, (i) => { workItemRangeProcessor(new DataParallelContext(IntRange.CreateFixed(i), workItemsCount)); }); } else { int workSize = workItemsCount / procCount; int mod = workItemsCount % procCount; if (mod == 0) { Parallel.For(0, procCount, (i) => { int begin = i * workSize; workItemRangeProcessor(new DataParallelContext(IntRange.CreateExclusive(begin, begin + workSize), workItemsCount)); }); } else { int to = 0; var spinLock = new SpinLock(false); Parallel.For(0, procCount, (i) => { int begin = to; bool lockTaken = false; try { spinLock.Enter(ref lockTaken); if (mod != 0) { to += workSize + 1; mod--; } else { to += workSize; } } finally { if (lockTaken) spinLock.Exit(); } workItemRangeProcessor(new DataParallelContext(IntRange.CreateExclusive(begin, to), workItemsCount)); }); } } }
public static void RunSpinLockTestExceptions() { SpinLock slock = new SpinLock(); bool isTaken = true; Assert.Throws<ArgumentException>(() => slock.Enter(ref isTaken)); // Failure Case: Enter didn't throw AE when isTaken is true slock = new SpinLock(false); Assert.Throws<InvalidOperationException>(() => { bool iHeld = slock.IsHeldByCurrentThread; }); // Failure Case: IsHeldByCurrentThread didn't throw IOE when the thread tracking is disabled }
/// <summary> /// Test TryEnter invalid cases /// </summary> /// <returns>True if succeeded, false otherwise</returns> private static bool RunSpinLockTest3_TryEnter(bool enableThreadIDs) { TestHarness.TestLog("SpinLock.TryEnter(invalid cases)"); Exception exception = null; SpinLock slock = new SpinLock(enableThreadIDs); bool lockTaken = false; #region Recursive lock if (enableThreadIDs) // only valid if thread IDs are on { // Test recursive locks slock.Enter(ref lockTaken); try { if (lockTaken) { bool dummy = false; // reacquire the lock slock.Enter(ref dummy); } } catch (Exception ex) { // LockRecursionException must be thrown exception = ex; } if (lockTaken) { slock.Exit(); //TODO: uncomment after finishing type forwarding in clr integration if (exception == null /*|| exception.GetType() != typeof(LockRecursionException)*/) { TestHarness.TestLog("SpinLock.TryEnter() failed, recursive locks without exception"); return false; } if (slock.IsHeldByCurrentThread) { TestHarness.TestLog("SpinLock.TryEnter() failed, IsHeld is true after calling Exit"); return false; } } else { return false; } } #endregion #region timeout > int.max // Test invalid argument handling, too long timeout exception = null; try { lockTaken = false; slock.TryEnter(TimeSpan.MaxValue, ref lockTaken); } catch (Exception ex) { exception = ex; } if (exception == null || exception.GetType() != typeof(ArgumentOutOfRangeException)) { TestHarness.TestLog(@"SpinLock.TryEnter() failed, timeout.Totalmilliseconds > int.maxValue without throwing ArgumentOutOfRangeException " + exception); return false; } #endregion #region Timeout > int.max // Test invalid argument handling, timeout < -1 exception = null; try { lockTaken = false; slock.TryEnter(-2, ref lockTaken); } catch (Exception ex) { exception = ex; } if (exception == null || exception.GetType() != typeof(ArgumentOutOfRangeException)) { TestHarness.TestLog(@"SpinLock.TryEnter() failed, timeout < -1 without throwing ArgumentOutOfRangeException"); return false; } #endregion TestHarness.TestLog("SpinLock.TryEnter() passed."); return true; }
/// <summary> /// Test TryEnter invalid cases /// </summary> /// <returns>True if succeeded, false otherwise</returns> private static void RunSpinLockTest3_TryEnter(bool enableThreadIDs) { Exception exception = null; SpinLock slock = new SpinLock(enableThreadIDs); bool lockTaken = false; #region Recursive lock if (enableThreadIDs) // only valid if thread IDs are on { // Test recursive locks slock.Enter(ref lockTaken); try { if (lockTaken) { bool dummy = false; // reacquire the lock slock.Enter(ref dummy); } } catch (Exception ex) { // LockRecursionException must be thrown exception = ex; } if (lockTaken) { slock.Exit(); if (exception == null || exception.GetType() != typeof(LockRecursionException)) { Assert.True(false, string.Format("SpinLock.TryEnter() failed, recursive locks without exception")); } if (slock.IsHeldByCurrentThread) { Assert.True(false, string.Format("SpinLock.TryEnter() failed, IsHeld is true after calling Exit")); } } else { Assert.True(false, string.Format("LockRecursionException was not thrown?")); } } #endregion #region timeout > int.max // Test invalid argument handling, too long timeout exception = null; try { lockTaken = false; slock.TryEnter(TimeSpan.MaxValue, ref lockTaken); } catch (Exception ex) { exception = ex; } if (exception == null || exception.GetType() != typeof(ArgumentOutOfRangeException)) { Assert.True(false, string.Format(@"SpinLock.TryEnter() failed, timeout.Totalmilliseconds > int.maxValue without throwing ArgumentOutOfRangeException " + exception)); } #endregion #region Timeout > int.max // Test invalid argument handling, timeout < -1 exception = null; try { lockTaken = false; slock.TryEnter(-2, ref lockTaken); } catch (Exception ex) { exception = ex; } if (exception == null || exception.GetType() != typeof(ArgumentOutOfRangeException)) { Assert.True(false, string.Format(@"SpinLock.TryEnter() failed, timeout < -1 without throwing ArgumentOutOfRangeException")); } #endregion }
/// <summary> /// Test Exit /// </summary> /// <returns>True if succeeded, false otherwise</returns> private static void RunSpinLockTest4_Exit(bool enableThreadIDs) { Exception exception = null; SpinLock slock = new SpinLock(enableThreadIDs); bool lockTaken = false; slock.Enter(ref lockTaken); slock.Exit(); if (enableThreadIDs) { if (slock.IsHeldByCurrentThread) { Assert.True(false, string.Format("SpinLock.Exit() failed, IsHeld is true after calling Exit")); } } else { if (slock.IsHeld) { Assert.True(false, string.Format("SpinLock.Exit() failed, IsHeld is true after calling Exit")); } } for (int i = 0; i < 2; i++) { bool useBarrier = i == 0; // Calling Exit without owning the lock try { slock.Exit(useBarrier); } catch (Exception ex) { // SynchronizationLockException must be thrown exception = ex; } } if (enableThreadIDs) { if (exception == null || exception.GetType() != typeof(SynchronizationLockException)) { Assert.True(false, string.Format(@"SpinLock.Exit() failed, calling Exit without owning the lock")); } } }
public static void EnterExit() { var sl = new SpinLock(); Assert.True(sl.IsThreadOwnerTrackingEnabled); for (int i = 0; i < 4; i++) { Assert.False(sl.IsHeld); Assert.False(sl.IsHeldByCurrentThread); bool lockTaken = false; if (i % 2 == 0) sl.Enter(ref lockTaken); else sl.TryEnter(ref lockTaken); Assert.True(lockTaken); Assert.True(sl.IsHeld); Assert.True(sl.IsHeldByCurrentThread); Task.Factory.StartNew(() => { Assert.True(sl.IsHeld); Assert.False(sl.IsHeldByCurrentThread); }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default).GetAwaiter().GetResult(); sl.Exit(); } }