public 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 Assert.Equal(threadsCount, succeeded); }
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(); } }
private int _lockReleased; //0 : true | 1 : false public SpinLockBlock(SpinLock lockTarget) { _lockTarget = lockTarget; var lockTaken = false; _lockTarget.Enter(ref lockTaken); if (lockTaken) { _lockReleased = FALSE; // false } }
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 }
public DisposableSpinLock(SpinLock thelock, bool tryLock) { this.mylock = thelock; if (tryLock) { mylock.TryEnter(ref isLocked); } else { mylock.Enter(ref isLocked); } }
static void Main() { #pragma warning disable 219 int x = 0; #pragma warning restore 219 const int iterations = 10000000; // 10 миллионов // Note: Сколько времени займет инкремент x 10 миллионов раз? Stopwatch stopwatch = Stopwatch.StartNew(); for (int i = 0; i < iterations; i++) { x++; } Console.WriteLine("Incrementing x: {0:N0}", stopwatch.ElapsedMilliseconds); // Note: Сколько времени займет инкремент x 10 миллионов раз, если // добавить вызов ничего не делающего метода? stopwatch.Restart(); for (int i = 0; i < iterations; i++) { Dummy(); x++; Dummy(); } Console.WriteLine("Incrementing x in Dummy: {0:N0}", stopwatch.ElapsedMilliseconds); // Note: Сколько времени займет инкремент x 10 миллионов раз, если // добавить вызов неконкурирующего объекта SpinLock var spinLock = new SpinLock(); stopwatch.Restart(); for (int i = 0; i < iterations; i++) { bool lockTaken = false; spinLock.Enter(ref lockTaken); x++; spinLock.Exit(); } Console.WriteLine("Incrementing x in SpinLock: {0:N0}", stopwatch.ElapsedMilliseconds); // Note: Сколько времени займет инкремент x 10 миллионов раз, если // добавить вызов неконкурирующего объекта SimpleWaitLock? using (var waitLock = new SimpleWaitLock()) { stopwatch.Restart(); for (int i = 0; i < iterations; i++) { waitLock.Enter(); x++; waitLock.Leave(); } Console.WriteLine("Incrementing x in SimpleWaitLock: {0:N0}", stopwatch.ElapsedMilliseconds); } }
public AsyncEntryBlockUC TryEnter() { using (SpinLock.Enter()) { if (LockStatus == Status.Locked) { return(AsyncEntryBlockUC.RefusedEntry); } LockStatus = Status.Locked; return(new AsyncEntryBlockUC(ExclusiveEntry)); } }
/// <summary> /// Reads the scan code from the device /// </summary> protected void ReadScanCode() { spinLock.Enter(); byte v = commandPort.Read8(); AddToFIFO(v); HAL.DebugWrite(" scancode: " + v.ToString() + " "); spinLock.Exit(); }
public bool TryGetInstance(bool throttle, float totalTime, out WrappedSoundEffectInstance result) { result = null; if (!(totalTime - lastPlayed > definition.MinimumTimeBetween) && throttle) { return(false); } bool lockTaken = false; spinLock.Enter(ref lockTaken); try { if (instanceCount < definition.InstanceLimit || !throttle) { instanceCount++; } else { return(false); } lastPlayed = totalTime; } finally { spinLock.Exit(); } var pooledObject = instancePool.GetFree(); result = pooledObject.Value; result.PoolObject = pooledObject; result.Instance.Volume = MathHelper.Clamp(RandomExt.GetRandomFloat(definition.MinVolume, definition.MaxVolume), 0, 1); result.Instance.Pitch = MathHelper.Clamp(RandomExt.GetRandomFloat(definition.MinPitchShift, definition.MaxPitchShift), 0, 1); return(true); }
private BindingInfo?GetBindingForType(Type type, string?exchange, string?topic, Func <string, string, BindingInfo> createBindingFunc) { BindingInfo info; bool lockTaken = false; try { _spinLock.Enter(ref lockTaken); if (!_exchages.TryGetValue(type, out info)) { var attr = type.GetCustomAttribute <ExchangeRouteAttribute>(); if (exchange == null) { exchange = attr?.Exchange ?? _globalExchange; if (exchange == null) { return(null); } } if (topic == null) { topic = attr?.Topic ?? type.Name; } info = createBindingFunc(exchange, topic); _exchages.Add(type, info); } return(info); } finally { if (lockTaken) { _spinLock.Exit(true); } } }
/// <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 { _lock.Enter(ref lockTaken); if (_index < buffers.Length) { buffer = buffers[_index]; buffers[_index++] = null; allocateBuffer = buffer == null; } } finally { if (lockTaken) { _lock.Exit(false); } } // 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]; } return(buffer); }
public ActorReference ActorOf <T> (string name, object initializationData, Mailbox mailbox) where T : Actor, new () { var reference = CreateActorReference(name, mailbox); Actor actor = new T(); actor.Self = reference; reference.State = ActorStates.Initializing; actor.Initialize(initializationData); var lockTaken = false; try { Spin.Enter(ref lockTaken); reference.State = ActorStates.Idle; mailbox.EnqueueActor(actor); } finally { if (lockTaken) { Spin.Exit(false); } } return(reference); }
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 < tasks.Length; i++) { // Create the 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++; } 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}", 10000); Console.WriteLine("Balance: {0}", account.Balance); // Wait for input before exiting Console.WriteLine("Press enter to finish"); Console.ReadLine(); }
public void Execute(ITashaHousehold household, int iteration) { var householdFitness = (float)EvaluateHousehold(household); bool taken = false; FitnessUpdateLock.Enter(ref taken); Thread.MemoryBarrier(); Fitness += householdFitness; if (taken) { FitnessUpdateLock.Exit(true); } }
protected override void InternalEnqueue(Action action) { bool lockTaken = false; try { _spinLock.Enter(ref lockTaken); _queue.Add(action); if (!_flushPending) { _taskFactory.StartNew(Flush); _flushPending = true; } } finally { if (lockTaken) { _spinLock.Exit(); } } }
public Memory Get() { var locked = false; try { queueLock.Enter(ref locked); if ((queue ?? throw new ObjectDisposedException(GetType().FullName)).Count > 0) { return(queue.Dequeue()); } } finally { if (locked) { queueLock.Exit(false); } } return(new Memory(this)); }
internal void Add(ITashaHousehold household) { var expansionFactor = household.ExpansionFactor; bool taken = false; Lock.Enter(ref taken); TotalExpansionFactor += expansionFactor; Households.Add(new ExpandedHousehold(household)); if (taken) { Lock.Exit(true); } }
internal unsafe byte[]? Receive(TKey key, byte *src, int chunkLength, int chunkOffset, int length) { if (!_bigDataBuffers.TryGetValue(key, out Buffer bdb)) { bool lockTaken = false; try { _bigDataBufferLock.Enter(ref lockTaken); if (!_bigDataBuffers.TryGetValue(key, out bdb)) { _bigDataBuffers.Add(key, bdb = Create(key, length)); } } finally { if (lockTaken) { _bigDataBufferLock.Exit(false); } } } fixed(byte *dst = bdb._data) { Mem.Cpy(dst + chunkOffset, src, chunkLength); } if (bdb.AddBytes(chunkLength) == 0) { Remove(key); return(bdb._data); } return(null); }
public static void MSSpinLock() { var ss2 = new SpinLock(); var number = 0; Parallel.For(0, 100000, (i) => { bool lockTaken = false; ss2.Enter(ref lockTaken); number++; ss2.Exit(); }); }
/// <summary> /// Returns whether a new item can be accepted, and increments a counter if it can. /// </summary> bool TryAdd() { bool lockTaken = false; try { batchCountLock.Enter(ref lockTaken); if (options.MaxNumberOfGroups != -1 && numberOfGroups + batchCount / BatchSize >= options.MaxNumberOfGroups) { return(false); } batchCount++; return(true); } finally { if (lockTaken) { batchCountLock.Exit(); } } }
public void Enqueue(Action continuation) { bool lockTaken = false; try { gate.Enter(ref lockTaken); if (dequing) { // Ensure Capacity if (waitingList.Length == waitingListCount) { var newLength = waitingListCount * 2; if ((uint)newLength > MaxArrayLength) newLength = MaxArrayLength; var newArray = new Action[newLength]; Array.Copy(waitingList, newArray, waitingListCount); waitingList = newArray; } waitingList[waitingListCount] = continuation; waitingListCount++; } else { // Ensure Capacity if (actionList.Length == actionListCount) { var newLength = actionListCount * 2; if ((uint)newLength > MaxArrayLength) newLength = MaxArrayLength; var newArray = new Action[newLength]; Array.Copy(actionList, newArray, actionListCount); actionList = newArray; } actionList[actionListCount] = continuation; actionListCount++; } } finally { if (lockTaken) gate.Exit(false); } }
public void SetParamValue(string variableName, string paramValue, object value) { if (_syncVariables.Contains(variableName)) { _syncVarLock.EnterWriteLock(); this._variables[variableName] = SetParamValue(paramValue, _variables[variableName], value); _syncVarLock.ExitWriteLock(); } else { this._variables[variableName] = SetParamValue(paramValue, _variables[variableName], value); } // 监视变量值如果被更新,则添加到值更新列表中,在状态上报时上传该值 if (_context.TraceVariables.Contains(variableName)) { bool getlock = false; _keyVarLock.Enter(ref getlock); _keyVariables.Add(variableName); _keyVarLock.Exit(); } }
public void Enqueue(T item) { var lockTaken = false; try { _sync.Enter(ref lockTaken); if (_consumer.TryDequeue(out var tcs)) { Debug.Assert(_producer.Count == 0); tcs.TrySetResult(item); } else { _producer.Enqueue(item); } } finally { _sync.Exit(false); } }
//TODO: SPEED UP THESE ENQUEUES! /// <summary> /// Enqueues an element to the tail of the queue with locking. /// </summary> /// <param name="item">Dequeued element, if any.</param> /// <returns>True if an element could be dequeued, false otherwise.</returns> public void Enqueue(T item) { //bool taken = false; //locker.Enter(ref taken); locker.Enter(); try { //Enqueues go to the tail only; it's like a queue. //head ----> tail if (count == array.Length) { //Resize //TODO: Better shift-resize T[] oldArray = array; array = new T[Math.Max(4, oldArray.Length * 2)]; //Copy the old first-end to the first part of the new array. Array.Copy(oldArray, firstIndex, array, 0, oldArray.Length - firstIndex); //Copy the old begin-first to the second part of the new array. Array.Copy(oldArray, 0, array, oldArray.Length - firstIndex, firstIndex); firstIndex = 0; lastIndex = count - 1; } lastIndex++; if (lastIndex == array.Length) { lastIndex = 0; } array[lastIndex] = item; count++; } finally { //Console.WriteLine("file: ConcurrentDeque, line: {0}", 80); locker.Exit(); } }
/// <summary> /// AutoRegister method could be very complicated if it should call generic Register method... /// No sanity checks, called from inside. /// </summary> private void InternalRegister(Type interfaceType, Func <object> getInstanceFunc, List <Type> otherTypesWeAreDependingOn) { RegisteredTypeContainer c = new RegisteredTypeContainer(this, interfaceType, getInstanceFunc, otherTypesWeAreDependingOn); bool gotLock = false; try { syncRoot.Enter(ref gotLock); registeredTypes[interfaceType] = c; } finally { if (gotLock) { syncRoot.Exit(); } } System.Diagnostics.Debug.WriteLine("{0} registered for {1} with dependencies: {2}", getInstanceFunc.Method.ToString(), interfaceType.ToString(), (otherTypesWeAreDependingOn != null) ? String.Join(", ", otherTypesWeAreDependingOn.ToList().Select(t => t.ToString()).ToArray()) : "-"); //LOCSTR }
// 异步flush的代码 private void FlushCallBack(object obj) { bool getLock = false; try { WriteLock.Enter(ref getLock); if (NoDataInStream == _hasDataInStream) { return; } LogStream.Flush(); Thread.VolatileWrite(ref _hasDataInStream, NoDataInStream); } finally { if (getLock) { WriteLock.Exit(); } } }
/// <summary> /// /// </summary> public void UpdateSlice(T dataT) { if (m_MultiThreadedCall == false && dataT.InLockProcessSlice() == false) { return; } m_LockSliceQueue.Enter(); { m_SliceQueue.Enqueue(dataT); } m_LockSliceQueue.Exit(); }
private void TryComplete() { var lockTaken = false; _lock.Enter(ref lockTaken); if (_isFileWriterProcessorFinished && _isTreeWriterInfoTaskProcessorFinished) { Completed(); } _lock.Exit(); }
public virtual Type CreateType(Type interfaceType, Type dynamicProxyBaseType) { Type ret; if (interfaceType == null) { throw new ArgumentNullException("interfaceType"); } if (dynamicProxyBaseType == null) { throw new ArgumentNullException("dynamicProxyBaseType"); } if (!TypeHelper.IsSubclassOf(dynamicProxyBaseType, typeof(DynamicProxy))) { throw new ArgumentException("dynamicProxyType must be a child of DynamicProxy"); //LOCSTR } string typeName = string.Concat(ownClassName, "+", interfaceType.FullName); bool gotLock = false; try { dynamicTypeEmitSyncRoot.Enter(ref gotLock); dynamicTypes.TryGetValue(typeName, out ret); if (ret == null) { TypeBuilder tb = moduleBuilder.DefineType(typeName, TypeAttributes.Public); tb.SetParent(dynamicProxyBaseType); tb.AddInterfaceImplementation(interfaceType); CreateConstructorBaseCalls(dynamicProxyBaseType, tb); DynamicImplementInterface(new List <Type> { interfaceType }, new List <string>(), interfaceType, tb); ret = tb.CreateType(); dynamicTypes.Add(typeName, ret); } } finally { if (gotLock) { dynamicTypeEmitSyncRoot.Exit(); } } return(ret); }
public void RunBenchmark() { int x = 0; const int iteration = 10000000; Stopwatch sw = Stopwatch.StartNew(); for (int i = 0; i < iteration; ++i) { ++x; } Console.WriteLine("{0:N0}", sw.ElapsedMilliseconds); sw.Restart(); for (int i = 0; i < iteration; ++i) { DoNothing(); x++; DoNothing(); } Console.WriteLine(sw.ElapsedMilliseconds); SpinLock sl = new SpinLock(false); sw.Restart(); for (int i = 0; i < iteration; ++i) { bool taken = false; sl.Enter(ref taken); x++; sl.Exit(); } Console.WriteLine(sw.ElapsedMilliseconds); using (SimpleWaitLock simpleWaitLock = new SimpleWaitLock()) { sw.Restart(); for (int i = 0; i < iteration; ++i) { simpleWaitLock.Enter(); x++; simpleWaitLock.Leave(); } Console.WriteLine(sw.ElapsedMilliseconds); } }
public static void TestMethod2() { /* * 在实际的编程中需要注意的是:不要将SpinLock声明为只读字段, * 如果声明为只读字段,会导致每次调用都会返回一个SpinLock新副本, * 在多线程下,每个方法都会成功获得锁,而受到保护的临界区不会按照预期进行串行化。 * */ SpinLock sl = new SpinLock(); CookTasks = new Task[Particpants]; Thread.Sleep(4000); Stopwatch swTask1 = new Stopwatch(); swTask1.Start(); for (var taskIndex = 0; taskIndex < Particpants; taskIndex++) { CookTasks[taskIndex] = Task.Factory.StartNew((num) => { Parallel.For(1, 200000, (i) => { var str = "append message " + i; bool lockTaken = false; try { sl.Enter(ref lockTaken); AppendStrMonitorLock.Append(str); } finally { if (lockTaken) { sl.Exit(); } } }); }, taskIndex); } /*ContinueWhenAll 提供一组任务完成后 延续方法*/ var finalTask = Task.Factory.ContinueWhenAll(CookTasks, (tasks) => { /*等待任务完成*/ Task.WaitAll(CookTasks); swTask1.Stop(); Console.WriteLine($"采用SpinLock操作,字符串长度:{AppendStrMonitorLock.Length},耗时:{swTask1.ElapsedMilliseconds}"); /*释放资源*/ }); Console.ReadLine(); }
public void QueueWorkItem([NotNull][Pooled] Action workItem) { bool lockTaken = false; bool startNewTask = false; PooledDelegateHelper.AddReference(workItem); try { spinLock.Enter(ref lockTaken); workItems.Enqueue(workItem); workAvailable.Set(); // We're only locking when potentially increasing aliveCount as we // don't want to go above our maximum amount of threads. int curBusyCount = Interlocked.CompareExchange(ref busyCount, 0, 0); int curAliveCount = Interlocked.CompareExchange(ref aliveCount, 0, 0); if (curBusyCount + 1 >= curAliveCount && curAliveCount < maxThreadCount) { // Start threads as busy otherwise only one thread will be created // when calling this function multiple times in a row Interlocked.Increment(ref busyCount); Interlocked.Increment(ref aliveCount); startNewTask = true; } } finally { if (lockTaken) { spinLock.Exit(true); } } // No point in wasting spins on the lock while creating the task if (startNewTask) { new Task(cachedTaskLoop, null, TaskCreationOptions.LongRunning).Start(); } }
/// <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 }
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 Exit /// </summary> /// <returns>True if succeeded, false otherwise</returns> private static void RunSpinLockTest4_Exit(bool enableThreadIDs) { SpinLock slock = new SpinLock(enableThreadIDs); bool lockTaken = false; slock.Enter(ref lockTaken); slock.Exit(); if (enableThreadIDs) { Assert.False(slock.IsHeldByCurrentThread); Assert.Throws<SynchronizationLockException>(() => slock.Exit(true)); Assert.Throws<SynchronizationLockException>(() => slock.Exit(false)); } else { Assert.False(slock.IsHeld); } }
/// <summary> /// Test TryEnter invalid cases /// </summary> /// <returns>True if succeeded, false otherwise</returns> private static void RunSpinLockTest3_TryEnter(bool enableThreadIDs) { 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); Assert.True(lockTaken); Assert.Throws<LockRecursionException>(() => { bool dummy = false; slock.Enter(ref dummy); }); slock.Exit(); Assert.False(slock.IsHeldByCurrentThread); } #endregion #region timeout > int.max // Test invalid argument handling, too long timeout Assert.Throws<ArgumentOutOfRangeException>(() => { bool lt = false; slock.TryEnter(TimeSpan.MaxValue, ref lt); }); #endregion timeout > int.max #region Timeout > int.max // Test invalid argument handling, timeout < -1 Assert.Throws<ArgumentOutOfRangeException>(() => { bool lt = false; slock.TryEnter(-2, ref lt); }); #endregion Timeout > int.max }
/// <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")); } } }