/// <summary> /// Enters an upgradeable lock (it is a read lock, but it can be upgraded). /// Only one upgradeable lock is allowed at a time. /// </summary> public void EnterUpgradeableLock() { //var spinWait = new SpinWait(); while (true) { LockIntegralType result = Interlocked.Add(ref _lockValue, _upgradeLockValue); if ((result >> _upgradeBitShift) == 1) { return; } Interlocked.Add(ref _lockValue, _upgradeUnlockValue); var spinCount = 0; while (true) { //spinWait.SpinOnce(); Spin.Wait(spinCount++); result = Interlocked.CompareExchange(ref _lockValue, _upgradeLockValue, 0); if (result == 0) { return; } if ((result >> _upgradeBitShift) == 0) { break; } } } }
/// <summary> /// Enters a read lock. /// </summary> public void EnterReadLock() { //var spinWait = new SpinWait(); while (true) { LockIntegralType result = Interlocked.Increment(ref _lockValue); if ((result >> _writeBitShift) == 0) { return; } Interlocked.Decrement(ref _lockValue); var spinCount = 0; while (true) { //spinWait.SpinOnce(); Spin.Wait(spinCount++); result = Interlocked.CompareExchange(ref _lockValue, 1, 0); if (result == 0) { return; } if ((result >> _writeBitShift) == 0) { break; } } } }
int _locked; // Resource lock: 0--free, 1--occupied /// <summary> /// Enters the lock, so you can do your actions in a safe manner. /// </summary> public void Enter() { if (Interlocked.CompareExchange(ref _locked, 1, 0) == 0) { return; } var spinCount = 0; while (Interlocked.CompareExchange(ref _locked, 1, 0) != 0) { Spin.Wait(spinCount++); } }
/// <summary> /// upgrades to write-lock. You must already own a Upgradeable lock and you must first exit the write lock then the Upgradeable lock. /// </summary> public void UncheckedUpgradeToWriteLock() { //var spinWait = new SpinWait(); LockIntegralType result = Interlocked.Add(ref _lockValue, _writeLockValue); var spinCount = 0; while ((result & _allReadsValue) != 0) { //spinWait.SpinOnce(); Spin.Wait(spinCount++); result = Interlocked.CompareExchange(ref _lockValue, 0, 0); } }
/// <summary> /// Enters write-lock. /// </summary> public void EnterWriteLock() { LockIntegralType result = Interlocked.CompareExchange(ref _lockValue, _writeLockValue, 0); if (result == 0) { return; } var spinCount = 0; //var spinWait = new SpinWait(); // we need to try again. for (int i = 0; i < 100; i++) { //spinWait.SpinOnce(); Spin.Wait(spinCount++); result = Interlocked.CompareExchange(ref _lockValue, _writeLockValue, 0); if (result == 0) { return; } // try to be the first locker. if ((result >> _writeBitShift) == 0) { break; } } // From this moment, we have priority. while (true) { result = Interlocked.Add(ref _lockValue, _writeLockValue); if (result == _writeLockValue) { return; } if ((result >> _writeBitShift) == 1) { spinCount = 0; // we obtained the write lock, but there may be readers, // so we wait until they release the lock. while (true) { //spinWait.SpinOnce(); Spin.Wait(spinCount++); result = Interlocked.CompareExchange(ref _lockValue, 0, 0); if (result == _writeLockValue) { return; } } } else { // we need to try again. Interlocked.Add(ref _lockValue, _writeUnlockValue); spinCount = 0; while (true) { //spinWait.SpinOnce(); Spin.Wait(spinCount++); result = Interlocked.CompareExchange(ref _lockValue, _writeLockValue, 0); if (result == 0) { return; } // try to be the first locker. if ((result >> _writeBitShift) == 0) { break; } } } } }